From e30f24997c3d0857f4521ec902a0604ca433f7c8 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Thu, 23 Jul 2026 16:55:42 +0900 Subject: [PATCH] init: ConditionPathExists service gate (systemd-style, with ! negation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit init's Service parser used deny_unknown_fields, so the C0 driver-manager service files (which use ConditionPathExists) were rejected wholesale — driver-manager stayed dormant by parser accident instead of by design. - service.rs: new optional ConditionPathExists field + condition_met() gate. A leading '!' negates: the service starts only when the path does NOT exist. - scheduler.rs: skip services whose condition is not met (status_skip, same pattern as skip_cmd). - 00_driver-manager.service: fix inverted polarity — the intent is 'run unless /etc/driver-manager.d/disabled exists', i.e. ConditionPathExists = "!/etc/driver-manager.d/disabled". - Drop two pre-existing unused imports (Write in service.rs, status_fail in main.rs). --- init.d/00_driver-manager.service | 2 +- init/src/main.rs | 2 +- init/src/scheduler.rs | 7 +++++++ init/src/service.rs | 19 ++++++++++++++++++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/init.d/00_driver-manager.service b/init.d/00_driver-manager.service index 990c999000..fae8661059 100644 --- a/init.d/00_driver-manager.service +++ b/init.d/00_driver-manager.service @@ -23,4 +23,4 @@ args = ["--rootfs"] type = "oneshot_async" # Operator must explicitly enable this service: # touch /etc/driver-manager.d/disabled # force fallback to pcid-spawner -ConditionPathExists = "/etc/driver-manager.d/disabled" +ConditionPathExists = "!/etc/driver-manager.d/disabled" diff --git a/init/src/main.rs b/init/src/main.rs index 94162e61d3..275275e64b 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -14,7 +14,7 @@ mod script; mod service; mod unit; -use crate::color::{init_error, init_warn, status_fail, status_ok}; +use crate::color::{init_error, init_warn, status_ok}; fn switch_stdio(stdio: &str) -> io::Result<()> { let stdin = libredox::Fd::open(stdio, O_RDONLY, 0)?; diff --git a/init/src/scheduler.rs b/init/src/scheduler.rs index 8ee2771c25..58ef2e0687 100644 --- a/init/src/scheduler.rs +++ b/init/src/scheduler.rs @@ -109,6 +109,13 @@ fn run(unit: &mut Unit, config: &mut InitConfig) { status_skip(&format!("Skipping {} ({})", desc, service.cmd)); return; } + if !service.condition_met() { + status_skip(&format!( + "Skipping {} (ConditionPathExists not met)", + desc + )); + return; + } if config.log_debug { init_info(&format!("Starting {} ({})", desc, service.cmd)); } else { diff --git a/init/src/service.rs b/init/src/service.rs index 27d9ec0338..2646da7f46 100644 --- a/init/src/service.rs +++ b/init/src/service.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsString; use std::fs::File; -use std::io::{self, Read, Write}; +use std::io::{self, Read}; use std::os::fd::{AsRawFd, FromRawFd, OwnedFd}; use std::os::unix::process::CommandExt; use std::process::Command; @@ -24,6 +24,8 @@ pub struct Service { pub inherit_envs: BTreeSet, #[serde(rename = "type")] pub type_: ServiceType, + #[serde(default, rename = "ConditionPathExists")] + pub condition_path_exists: Option, } #[derive(Clone, Debug, Default, Deserialize)] @@ -36,6 +38,21 @@ pub enum ServiceType { OneshotAsync, } +impl Service { + /// systemd-style ConditionPathExists gate. A leading `!` negates the + /// test: the service starts only when the path does NOT exist. + pub fn condition_met(&self) -> bool { + let Some(cond) = &self.condition_path_exists else { + return true; + }; + let (negated, path) = match cond.strip_prefix('!') { + Some(rest) => (true, rest), + None => (false, cond.as_str()), + }; + std::path::Path::new(path).exists() != negated + } +} + fn create_pipe() -> io::Result<(File, OwnedFd)> { let mut fds = [0i32; 2]; // Use libc::pipe2() which goes through relibc's FILETABLE-managed path