From 73cc0b0a07cc9656b4f013d26b280972fe3aee17 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:57:42 +0100 Subject: [PATCH] init: Begin introducing units Dependencies are not yet functional. --- init.d/00_nulld.service | 9 +++-- init.d/00_randd.service | 13 +++++-- init.d/00_rtcd.service | 7 ++-- init.d/00_zerod.service | 9 +++-- init/src/main.rs | 34 ++++++++++-------- init/src/script.rs | 8 ++--- init/src/unit.rs | 76 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 28 deletions(-) create mode 100644 init/src/unit.rs diff --git a/init.d/00_nulld.service b/init.d/00_nulld.service index 102db8c530..70063c252c 100644 --- a/init.d/00_nulld.service +++ b/init.d/00_nulld.service @@ -1,4 +1,9 @@ { - "cmd": "nulld", - "type": { "scheme": "null" } + "unit": {}, + "service": { + "cmd": "nulld", + "type": { + "scheme": "null" + } + } } diff --git a/init.d/00_randd.service b/init.d/00_randd.service index 886efa0a2c..d0feb1c3fb 100644 --- a/init.d/00_randd.service +++ b/init.d/00_randd.service @@ -1,5 +1,12 @@ { - "cmd": "randd", - "args": ["rand"], - "type": { "scheme": "rand" } + "unit": {}, + "service": { + "cmd": "randd", + "args": [ + "rand" + ], + "type": { + "scheme": "rand" + } + } } diff --git a/init.d/00_rtcd.service b/init.d/00_rtcd.service index ea7ebece99..c7c781ba46 100644 --- a/init.d/00_rtcd.service +++ b/init.d/00_rtcd.service @@ -1,4 +1,7 @@ { - "cmd": "rtcd", - "type": "oneshot" + "unit": {}, + "service": { + "cmd": "rtcd", + "type": "oneshot" + } } diff --git a/init.d/00_zerod.service b/init.d/00_zerod.service index e612aaa9c3..78916b7ea2 100644 --- a/init.d/00_zerod.service +++ b/init.d/00_zerod.service @@ -1,4 +1,9 @@ { - "cmd": "zerod", - "type": { "scheme": "zero" } + "unit": {}, + "service": { + "cmd": "zerod", + "type": { + "scheme": "zero" + } + } } diff --git a/init/src/main.rs b/init/src/main.rs index 04da484ddb..a836075a3c 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,16 +1,17 @@ use std::collections::BTreeMap; -use std::ffi::{OsStr, OsString}; +use std::env; +use std::ffi::OsString; use std::io::Result; use std::path::Path; -use std::{env, fs}; use libredox::flag::{O_RDONLY, O_WRONLY}; use crate::script::Command; -use crate::service::Service; +use crate::unit::Unit; mod script; mod service; +mod unit; fn switch_stdio(stdio: &str) -> Result<()> { let stdin = libredox::Fd::open(stdio, O_RDONLY, 0)?; @@ -75,23 +76,26 @@ fn switch_root(prefix: &Path, etcdir: &Path, config: &mut InitConfig) { } fn run(file: &Path, config: &mut InitConfig) -> Result<()> { - if file.extension() == Some(OsStr::new("service")) { - let service: Service = serde_json::from_str(&fs::read_to_string(file).unwrap()).unwrap(); - service.spawn(&config.envs); - return Ok(()); - } - - let (script, errors) = script::Script::from_file(file)?; - + let (unit, errors) = Unit::from_file(file)?; for error in errors { eprintln!("init: {}: {error}", file.display()); } - for cmd in script.0 { - if config.log_debug { - eprintln!("init: running: {cmd:?}"); + match unit.kind { + unit::UnitKind::LegacyScript { script } => { + for cmd in script.0 { + if config.log_debug { + eprintln!("init: running: {cmd:?}"); + } + run_command(cmd, config); + } + } + unit::UnitKind::Service { service } => { + if config.log_debug { + eprintln!("init: running: {} {}", service.cmd, service.args.join(" ")); + } + service.spawn(&config.envs); } - run_command(cmd, config); } Ok(()) diff --git a/init/src/script.rs b/init/src/script.rs index bd0de5161c..862436f4c6 100644 --- a/init/src/script.rs +++ b/init/src/script.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use std::path::{Path, PathBuf}; -use std::{env, fs, io, iter}; +use std::path::PathBuf; +use std::{env, io, iter}; use crate::service::{Service, ServiceType}; @@ -15,11 +15,11 @@ fn subst_env<'a>(arg: &str) -> String { pub struct Script(pub Vec); impl Script { - pub fn from_file(file: &Path) -> io::Result<(Script, Vec)> { + pub fn from_str(config: &str) -> io::Result<(Script, Vec)> { let mut cmds = vec![]; let mut errors = vec![]; - for line_raw in fs::read_to_string(file)?.lines() { + for line_raw in config.lines() { let line = line_raw.trim(); if line.is_empty() || line.starts_with('#') { continue; diff --git a/init/src/unit.rs b/init/src/unit.rs new file mode 100644 index 0000000000..f74544eddc --- /dev/null +++ b/init/src/unit.rs @@ -0,0 +1,76 @@ +use std::path::Path; +use std::{fs, io}; + +use serde::Deserialize; + +use crate::script::Script; +use crate::service::Service; + +pub struct Unit { + pub name: String, + + pub info: UnitInfo, + pub kind: UnitKind, +} + +#[derive(Deserialize)] +pub struct UnitInfo { + #[serde(default)] + description: String, + #[serde(default)] + requires: Vec, + #[serde(default)] + requires_weak: Vec, +} + +pub enum UnitKind { + LegacyScript { script: Script }, + Service { service: Service }, +} + +#[derive(Deserialize)] +struct SerializedService { + unit: UnitInfo, + service: Service, +} + +impl Unit { + pub fn from_file(config_path: &Path) -> io::Result<(Self, Vec)> { + let name = config_path + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + + let config = fs::read_to_string(config_path)?; + + let (info, kind, errors) = match config_path.extension().map(|ext| ext.to_str().unwrap()) { + None => { + let (script, warnings) = Script::from_str(&config)?; + ( + UnitInfo { + description: "".to_owned(), + requires: vec![], + requires_weak: vec![], + }, + UnitKind::LegacyScript { script }, + warnings, + ) + } + Some("service") => { + let service: SerializedService = serde_json::from_str(&config)?; + ( + service.unit, + UnitKind::Service { + service: service.service, + }, + vec![], + ) + } + Some(_) => return Err(io::Error::other("invalid file extension")), + }; + + Ok((Unit { name, info, kind }, errors)) + } +}