init: ConditionPathExists service gate (systemd-style, with ! negation)

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).
This commit is contained in:
Red Bear OS
2026-07-23 16:55:42 +09:00
parent c836fffb66
commit e30f24997c
4 changed files with 27 additions and 3 deletions
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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)?;
+7
View File
@@ -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 {
+18 -1
View File
@@ -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<String>,
#[serde(rename = "type")]
pub type_: ServiceType,
#[serde(default, rename = "ConditionPathExists")]
pub condition_path_exists: Option<String>,
}
#[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