diff --git a/local/patches/base/P0-daemon-silence-init-notify.patch b/local/patches/base/P0-daemon-comprehensive-fix.patch similarity index 66% rename from local/patches/base/P0-daemon-silence-init-notify.patch rename to local/patches/base/P0-daemon-comprehensive-fix.patch index 84e6e9c120..071d4b52e7 100644 --- a/local/patches/base/P0-daemon-silence-init-notify.patch +++ b/local/patches/base/P0-daemon-comprehensive-fix.patch @@ -1,21 +1,13 @@ diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs +index 9f507221..2d092b0b 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs -@@ -10,26 +10,35 @@ use libredox::Fd; - use redox_scheme::scheme::{SchemeAsync, SchemeSync}; +@@ -10,15 +10,35 @@ use libredox::Fd; use redox_scheme::Socket; + use redox_scheme::scheme::{SchemeAsync, SchemeSync}; -unsafe fn get_fd(var: &str) -> RawFd { -- let fd: RawFd = match std::env::var(var) -- .map_err(|e| eprintln!("daemon: env var {var} not set: {e}")) -- .ok() -- .and_then(|val| { -- val.parse() -- .map_err(|e| eprintln!("daemon: failed to parse {var} as fd: {e}")) -- .ok() -- }) { -- Some(fd) => fd, -- None => return -1, +- let fd: RawFd = std::env::var(var).unwrap().parse().unwrap(); +unsafe fn get_fd(var: &str) -> Option { + let value = match std::env::var(var) { + Ok(value) => value, @@ -36,13 +28,13 @@ diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs + eprintln!("daemon: invalid {var} value {value:?} for {exe}: {err}; readiness notification disabled"); + return None; + } - }; ++ }; if unsafe { libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC) } == -1 { - eprintln!( +- panic!( ++ eprintln!( "daemon: failed to set CLOEXEC flag for {var} fd: {}", io::Error::last_os_error() ); -- return -1; + return None; } - fd @@ -50,7 +42,7 @@ diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs } unsafe fn pass_fd(cmd: &mut Command, env: &str, fd: OwnedFd) { -@@ -47,22 +56,20 @@ unsafe fn pass_fd(cmd: &mut Command, env: &str, fd: OwnedFd) { +@@ -38,20 +58,22 @@ unsafe fn pass_fd(cmd: &mut Command, env: &str, fd: OwnedFd) { /// A long running background process that handles requests. #[must_use = "Daemon::ready must be called"] pub struct Daemon { @@ -62,23 +54,21 @@ diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs /// Create a new daemon. pub fn new(f: impl FnOnce(Daemon) -> !) -> ! { - let write_pipe = unsafe { io::PipeWriter::from_raw_fd(get_fd("INIT_NOTIFY")) }; -+ let write_pipe = unsafe { get_fd("INIT_NOTIFY").map(io::PipeWriter::from_raw_fd) }; ++ let write_pipe = get_fd("INIT_NOTIFY").map(|fd| unsafe { io::PipeWriter::from_raw_fd(fd) }); f(Daemon { write_pipe }) } /// Notify the process that the daemon is ready to accept requests. pub fn ready(mut self) { -- if let Err(err) = self.write_pipe.write_all(&[0]) { -- if err.kind() != io::ErrorKind::BrokenPipe { -- eprintln!("daemon::ready write failed: {err}"); -- } +- self.write_pipe.write_all(&[0]).unwrap(); + if let Some(write_pipe) = self.write_pipe.as_mut() { + write_pipe.write_all(&[0]).unwrap(); - } ++ } } -@@ -87,24 +94,26 @@ impl Daemon { + /// Executes `Command` as a child process. +@@ -83,21 +105,25 @@ impl Daemon { /// A long running background process that handles requests using schemes. #[must_use = "SchemeDaemon::ready must be called"] pub struct SchemeDaemon { @@ -90,26 +80,20 @@ diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs /// Create a new daemon for use with schemes. pub fn new(f: impl FnOnce(SchemeDaemon) -> !) -> ! { - let write_pipe = unsafe { io::PipeWriter::from_raw_fd(get_fd("INIT_NOTIFY")) }; -+ let write_pipe = unsafe { get_fd("INIT_NOTIFY").map(io::PipeWriter::from_raw_fd) }; ++ let write_pipe = get_fd("INIT_NOTIFY").map(|fd| unsafe { io::PipeWriter::from_raw_fd(fd) }); f(SchemeDaemon { write_pipe }) } /// Notify the process that the scheme daemon is ready to accept requests. pub fn ready_with_fd(self, cap_fd: Fd) -> syscall::Result<()> { -- syscall::call_wo( ++ let write_pipe = match self.write_pipe { ++ Some(pipe) => pipe, ++ None => return Ok(()), ++ }; + syscall::call_wo( - self.write_pipe.as_raw_fd() as usize, -- &cap_fd.into_raw().to_ne_bytes(), -- syscall::CallFlags::FD, -- &[], -- )?; -+ if let Some(write_pipe) = self.write_pipe { -+ syscall::call_wo( -+ write_pipe.as_raw_fd() as usize, -+ &cap_fd.into_raw().to_ne_bytes(), -+ syscall::CallFlags::FD, -+ &[], -+ )?; -+ } - Ok(()) - } ++ write_pipe.as_raw_fd() as usize, + &cap_fd.into_raw().to_ne_bytes(), + syscall::CallFlags::FD, + &[], diff --git a/local/patches/base/P0-daemon-init-notify-graceful.patch b/local/patches/base/P0-daemon-init-notify-graceful.patch deleted file mode 100644 index ce1292f01b..0000000000 --- a/local/patches/base/P0-daemon-init-notify-graceful.patch +++ /dev/null @@ -1,55 +0,0 @@ -From: Red Bear OS -Date: 2026-04-28 -Subject: daemon: handle missing INIT_NOTIFY gracefully instead of panicking - -The Daemon::new() and Daemon::ready() functions in the daemon library -called unwrap() on the INIT_NOTIFY environment variable and the ready -pipe write, causing a hard panic when a daemon is started outside the -init system's notification pipe mechanism. - -Replace unwrap() with graceful error handling: -- get_fd() returns -1 if the env var is missing or invalid, logging - a warning via eprintln -- ready() logs a warning on write failure instead of panicking - -diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs -index 9f507221..a0ba9d88 100644 ---- a/daemon/src/lib.rs -+++ b/daemon/src/lib.rs -@@ -11,12 +11,23 @@ use redox_scheme::Socket; - use redox_scheme::scheme::{SchemeAsync, SchemeSync}; - - unsafe fn get_fd(var: &str) -> RawFd { -- let fd: RawFd = std::env::var(var).unwrap().parse().unwrap(); -+ let fd: RawFd = match std::env::var(var) -+ .map_err(|e| eprintln!("daemon: env var {var} not set: {e}")) -+ .ok() -+ .and_then(|val| { -+ val.parse() -+ .map_err(|e| eprintln!("daemon: failed to parse {var} as fd: {e}")) -+ .ok() -+ }) { -+ Some(fd) => fd, -+ None => return -1, -+ }; - if unsafe { libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC) } == -1 { -- panic!( -+ eprintln!( - "daemon: failed to set CLOEXEC flag for {var} fd: {}", - io::Error::last_os_error() - ); -+ return -1; - } - fd - } -@@ -50,7 +61,9 @@ impl Daemon { - - /// Notify the process that the daemon is ready to accept requests. - pub fn ready(mut self) { -- self.write_pipe.write_all(&[0]).unwrap(); -+ if let Err(err) = self.write_pipe.write_all(&[0]) { -+ eprintln!("daemon::ready write failed: {err}"); -+ } - } - - /// Executes `Command` as a child process. diff --git a/recipes/core/base/recipe.toml b/recipes/core/base/recipe.toml index 70a9daa3b2..4a4659e347 100644 --- a/recipes/core/base/recipe.toml +++ b/recipes/core/base/recipe.toml @@ -3,6 +3,7 @@ git = "https://gitlab.redox-os.org/redox-os/base.git" rev = "463f76b9608a896e6f6c9f63457f57f6409873c7" patches = [ "P0-redox-scheme-bump-0.11.1.patch", + "P0-daemon-comprehensive-fix.patch", "P0-add-missing-driver-members.patch", "P0-init-continuous-scheduling.patch", "P0-dhcpd-auto-iface.patch",