Complete base patch split and update rust toolchain

Base patch extraction (12 new patches, 11,017 lines from the 17k monolith):
- P2-acpid-core-refactor: acpi.rs, dmar, aml_physmem, ec, scheme (3,150 lines)
- P2-ihdad-device-refactor: CodecTopology, ControllerPolicy, InputStream (1,022 lines)
- P2-ac97d-ihdad-main: AC97 + ihdad daemon error handling (287 lines)
- P2-inputd: inputd lib + main with named producers (896 lines)
- P2-network-driver-mains: e1000/ixgbe/rtl8139/rtl8168d/virtio-net mains (607 lines)
- P2-pcid-driver-interface: BAR, cap, config, IRQ helpers, MSI, scheme (1,463 lines)
- P2-storage-driver-mains: ahcid/ided/nvmed/virtio-blk main.rs files (625 lines)
- P2-xhcid-remaining: xhcid main, device_enumerator, xhci mod+scheme (2,033 lines)
- P2-virtio-core-vbox: virtio-core arch/probe/transport + vboxd (413 lines)
- P2-init-subsystems: scheduler, service, unit management (292 lines)
- P2-logd: logd main + scheme (164 lines)
- P2-hwd-misc: hwd Cargo.toml + main.rs (64 lines)

Graphics drivers (ihdgd, vesad, virtio-gpud, fbcond scheme/text, graphics-ipc)
already fully covered by existing P2-daemon-hardening.patch — no duplicates created.

Rust toolchain: nightly-2025-10-03 → nightly-2026-04-01 (1.96.0-nightly).
Cookbook builds clean, no feature gates in codebase.
This commit is contained in:
2026-04-25 19:30:53 +01:00
parent 65acab85bb
commit 220f053ad8
13 changed files with 11017 additions and 1 deletions
+292
View File
@@ -0,0 +1,292 @@
# P2-init-subsystems.patch
# Extract init subsystem hardening: service respawn, unit store Option returns,
# scheduler PID tracking, and service spawn error handling.
#
# Files: init/src/scheduler.rs, init/src/service.rs, init/src/unit.rs
diff --git a/init/src/scheduler.rs b/init/src/scheduler.rs
index d42a4e57..64e64e1e 100644
--- a/init/src/scheduler.rs
+++ b/init/src/scheduler.rs
@@ -5,6 +5,7 @@ use crate::unit::{Unit, UnitId, UnitKind, UnitStore};
pub struct Scheduler {
pending: VecDeque<Job>,
+ pub respawn_pids: Vec<(UnitId, u32)>,
}
struct Job {
@@ -20,6 +21,7 @@ impl Scheduler {
pub fn new() -> Scheduler {
Scheduler {
pending: VecDeque::new(),
+ respawn_pids: Vec::new(),
}
}
@@ -43,7 +45,10 @@ impl Scheduler {
) {
let loaded_units = unit_store.load_units(unit_id.clone(), errors);
for unit_id in loaded_units {
- if !unit_store.unit(&unit_id).conditions_met() {
+ let Some(unit) = unit_store.unit(&unit_id) else {
+ continue;
+ };
+ if !unit.conditions_met() {
continue;
}
@@ -62,7 +67,10 @@ impl Scheduler {
match job.kind {
JobKind::Start => {
- let unit = unit_store.unit_mut(&job.unit);
+ let Some(unit) = unit_store.unit_mut(&job.unit) else {
+ eprintln!("init: unit {} not found in store, skipping", job.unit.0);
+ continue 'a;
+ };
for dep in &unit.info.requires_weak {
for pending_job in &self.pending {
@@ -73,14 +81,17 @@ impl Scheduler {
}
}
- run(unit, init_config);
+ let pid = run(unit, init_config);
+ if let Some(pid) = pid {
+ self.respawn_pids.push((job.unit.clone(), pid));
+ }
}
}
}
}
}
-fn run(unit: &mut Unit, config: &mut InitConfig) {
+fn run(unit: &mut Unit, config: &mut InitConfig) -> Option<u32> {
match &unit.kind {
UnitKind::LegacyScript { script } => {
for cmd in script.clone() {
@@ -92,25 +103,30 @@ fn run(unit: &mut Unit, config: &mut InitConfig) {
}
UnitKind::Service { service } => {
if config.skip_cmd.contains(&service.cmd) {
- eprintln!("Skipping '{} {}'", service.cmd, service.args.join(" "));
- return;
+ eprintln!("init: skipping {} {}", service.cmd, service.args.join(" "));
+ return None;
}
- if config.log_debug {
+ eprintln!(
+ "init: starting {} ({})",
+ unit.info.description.as_ref().unwrap_or(&unit.id.0),
+ service.cmd,
+ );
+ let pid = service.spawn(&config.envs);
+ if pid.is_some() {
eprintln!(
- "Starting {} ({})",
+ "init: started {} (pid {})",
unit.info.description.as_ref().unwrap_or(&unit.id.0),
- service.cmd,
+ pid.unwrap_or(0),
);
}
- service.spawn(&config.envs);
+ return pid;
}
UnitKind::Target {} => {
- if config.log_debug {
- eprintln!(
- "Reached target {}",
- unit.info.description.as_ref().unwrap_or(&unit.id.0),
- );
- }
+ eprintln!(
+ "init: reached target {}",
+ unit.info.description.as_ref().unwrap_or(&unit.id.0),
+ );
}
}
+ None
}
diff --git a/init/src/service.rs b/init/src/service.rs
index ed0023e9..cc95d02b 100644
--- a/init/src/service.rs
+++ b/init/src/service.rs
@@ -22,6 +22,8 @@ pub struct Service {
pub inherit_envs: BTreeSet<String>,
#[serde(rename = "type")]
pub type_: ServiceType,
+ #[serde(default)]
+ pub respawn: bool,
}
#[derive(Clone, Debug, Default, Deserialize)]
@@ -35,7 +37,7 @@ pub enum ServiceType {
}
impl Service {
- pub fn spawn(&self, base_envs: &BTreeMap<String, OsString>) {
+ pub fn spawn(&self, base_envs: &BTreeMap<String, OsString>) -> Option<u32> {
let mut command = Command::new(&self.cmd);
command.args(self.args.iter().map(|arg| subst_env(arg)));
command.env_clear();
@@ -46,20 +48,28 @@ impl Service {
}
command.envs(base_envs).envs(&self.envs);
- let (mut read_pipe, write_pipe) = io::pipe().unwrap();
+ let (mut read_pipe, write_pipe) = match io::pipe() {
+ Ok(pair) => pair,
+ Err(err) => {
+ eprintln!("init: failed to create readiness pipe for {:?}: {err}", command);
+ return None;
+ }
+ };
unsafe { pass_fd(&mut command, "INIT_NOTIFY", write_pipe.into()) };
let mut child = match command.spawn() {
Ok(child) => child,
Err(err) => {
eprintln!("init: failed to execute {:?}: {}", command, err);
- return;
+ return None;
}
};
match &self.type_ {
ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
- Ok(()) => {}
+ Ok(()) => {
+ eprintln!("init: {} ready (notify)", self.cmd);
+ }
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
eprintln!("init: {command:?} exited without notifying readiness");
}
@@ -81,23 +91,34 @@ impl Service {
}) => continue,
Ok(0) => {
eprintln!("init: {command:?} exited without notifying readiness");
- return;
+ return None;
}
Ok(1) => break,
Ok(n) => {
eprintln!("init: incorrect amount of fds {n} returned");
- return;
+ return None;
}
Err(err) => {
eprintln!("init: failed to wait for {command:?}: {err}");
- return;
+ return None;
}
}
}
- let current_namespace_fd = libredox::call::getns().expect("TODO");
- libredox::call::register_scheme_to_ns(current_namespace_fd, scheme, new_fd)
- .expect("TODO");
+ let current_namespace_fd = match libredox::call::getns() {
+ Ok(fd) => fd,
+ Err(err) => {
+ eprintln!("init: failed to get current namespace for {command:?}: {err}");
+ return None;
+ }
+ };
+ if let Err(err) =
+ libredox::call::register_scheme_to_ns(current_namespace_fd, scheme, new_fd)
+ {
+ eprintln!("init: failed to register scheme {scheme:?} for {command:?}: {err}");
+ } else {
+ eprintln!("init: {} ready (scheme {})", self.cmd, scheme);
+ }
}
ServiceType::Oneshot => {
drop(read_pipe);
@@ -105,6 +126,8 @@ impl Service {
Ok(exit_status) => {
if !exit_status.success() {
eprintln!("init: {command:?} failed with {exit_status}");
+ } else {
+ eprintln!("init: {} done (oneshot)", self.cmd);
}
}
Err(err) => {
@@ -112,8 +135,13 @@ impl Service {
}
}
}
- ServiceType::OneshotAsync => {}
+ ServiceType::OneshotAsync => {
+ if self.respawn {
+ return Some(child.id());
+ }
+ }
}
+ None
}
}
diff --git a/init/src/unit.rs b/init/src/unit.rs
index 98053cb2..a58bfb96 100644
--- a/init/src/unit.rs
+++ b/init/src/unit.rs
@@ -23,8 +23,14 @@ impl UnitStore {
}
pub fn set_runtime_target(&mut self, unit_id: UnitId) {
- assert!(self.runtime_target.is_none());
- assert!(self.units.contains_key(&unit_id));
+ if self.runtime_target.is_some() {
+ eprintln!("init: runtime target already set, ignoring {}", unit_id.0);
+ return;
+ }
+ if !self.units.contains_key(&unit_id) {
+ eprintln!("init: runtime target {} not found in unit store", unit_id.0);
+ return;
+ }
self.runtime_target = Some(unit_id);
}
@@ -85,8 +91,10 @@ impl UnitStore {
let unit = self.load_single_unit(unit_id, errors);
if let Some(unit) = unit {
loaded_units.push(unit.clone());
- for dep in &self.unit(&unit).info.requires_weak {
- pending_units.push(dep.clone());
+ if let Some(u) = self.unit(&unit) {
+ for dep in &u.info.requires_weak {
+ pending_units.push(dep.clone());
+ }
}
}
}
@@ -94,12 +102,12 @@ impl UnitStore {
loaded_units
}
- pub fn unit(&self, unit: &UnitId) -> &Unit {
- self.units.get(unit).unwrap()
+ pub fn unit(&self, unit: &UnitId) -> Option<&Unit> {
+ self.units.get(unit)
}
- pub fn unit_mut(&mut self, unit: &UnitId) -> &mut Unit {
- self.units.get_mut(unit).unwrap()
+ pub fn unit_mut(&mut self, unit: &UnitId) -> Option<&mut Unit> {
+ self.units.get_mut(unit)
}
}
@@ -180,7 +188,7 @@ impl Unit {
) -> io::Result<Self> {
let config = fs::read_to_string(config_path)?;
- let Some(ext) = config_path.extension().map(|ext| ext.to_str().unwrap()) else {
+ let Some(ext) = config_path.extension().and_then(|ext| ext.to_str()) else {
let script = Script::from_str(&config, errors)?;
return Ok(Unit {
id,