cee25393d8
- Fix P15-8-init-cycle-detection.patch: replace visiting+error with seen+silent-skip to eliminate 11 false-positive 'dependency cycle detected' errors on shared deps - Fix P0-daemon-fix-init-notify-unwrap.patch: remove eprintln! for missing INIT_NOTIFY (expected for oneshot_async services, ~7 daemons affected) - Fix driver-manager hotplug loop: add PERMANENTLY_SKIPPED static set shared between hotplug handler and DriverConfig::probe() to stop infinite re-probing of Fatal/NotSupported/deferred-exhausted device+driver pairs (e.g. ided) - Fix driver-manager log_timeline: suppress repeated EPIPE/ENOENT errors with AtomicI32 dedup and AtomicBool one-shot guards for boot timeline JSON - Add driver-manager SIGTERM handler, ACPI bus registration, --status mode, driver reap loop, graceful shutdown, and reduced deferred retries (30→3)
80 lines
3.5 KiB
Diff
80 lines
3.5 KiB
Diff
--- 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::io::Read;
|
|
-use std::os::fd::{AsRawFd, OwnedFd};
|
|
+use std::os::fd::{AsRawFd, OwnedFd, RawFd};
|
|
use std::os::unix::process::CommandExt;
|
|
use std::process::Command;
|
|
use std::{env, io};
|
|
@@ -11,6 +11,23 @@
|
|
use crate::color::{init_error, init_warn, status_fail};
|
|
use crate::script::subst_env;
|
|
|
|
+/// Default timeout in seconds for waiting for service readiness notification.
|
|
+/// Prevents boot from hanging indefinitely if a daemon fails to notify.
|
|
+const SERVICE_READY_TIMEOUT_SECS: u32 = 30;
|
|
+
|
|
+/// Wait for data to be available on a file descriptor, with a timeout.
|
|
+/// Returns true if data is ready, false if timed out.
|
|
+fn poll_fd_timeout(fd: RawFd, timeout_secs: u32) -> bool {
|
|
+ let mut pollfd = libc::pollfd {
|
|
+ fd,
|
|
+ events: libc::POLLIN,
|
|
+ revents: 0,
|
|
+ };
|
|
+ let timeout_ms = (timeout_secs as libc::c_int) * 1000;
|
|
+ let result = unsafe { libc::poll(&mut pollfd, 1, timeout_ms) };
|
|
+ result > 0
|
|
+}
|
|
+
|
|
#[derive(Clone, Debug, Deserialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct Service {
|
|
@@ -75,16 +92,36 @@
|
|
let _ = unsafe { libc::close(write_raw) };
|
|
|
|
match &self.type_ {
|
|
- ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
|
|
- Ok(()) => {}
|
|
- Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
|
|
- init_warn(&format!("{:?} exited without notifying readiness", command));
|
|
+ ServiceType::Notify => {
|
|
+ if !poll_fd_timeout(read_pipe.as_raw_fd(), SERVICE_READY_TIMEOUT_SECS) {
|
|
+ init_warn(&format!(
|
|
+ "{:?} timed out after {}s waiting for readiness",
|
|
+ command, SERVICE_READY_TIMEOUT_SECS
|
|
+ ));
|
|
+ let _ = child.kill();
|
|
+ let _ = child.wait();
|
|
+ return;
|
|
}
|
|
- Err(err) => {
|
|
- init_error(&format!("failed to wait for {:?}: {}", command, err));
|
|
+ match read_pipe.read_exact(&mut [0]) {
|
|
+ Ok(()) => {}
|
|
+ Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
|
|
+ init_warn(&format!("{:?} exited without notifying readiness", command));
|
|
+ }
|
|
+ Err(err) => {
|
|
+ init_error(&format!("failed to wait for {:?}: {}", command, err));
|
|
+ }
|
|
}
|
|
- },
|
|
+ }
|
|
ServiceType::Scheme(scheme) => {
|
|
+ if !poll_fd_timeout(read_pipe.as_raw_fd(), SERVICE_READY_TIMEOUT_SECS) {
|
|
+ init_warn(&format!(
|
|
+ "{:?} timed out after {}s waiting for scheme registration",
|
|
+ command, SERVICE_READY_TIMEOUT_SECS
|
|
+ ));
|
|
+ let _ = child.kill();
|
|
+ let _ = child.wait();
|
|
+ return;
|
|
+ }
|
|
let mut new_fd = usize::MAX;
|
|
loop {
|
|
match syscall::call_ro(
|