6c440d0d03
The previous daemon patches (P0-daemon-init-notify-graceful, P0-daemon-fix-init-notify-unwrap,
P0-daemon-silence-init-notify) were conflicting with each other and with
the upstream daemon code. The result was either:
1. get_fd returns RawFd (-1) but Daemon.write_pipe is Option<PipeWriter>
(from P0-daemon-init-notify-graceful) — broken
2. get_fd returns Option<RawFd> but Daemon::new uses io::PipeWriter::from_raw_fd
(no .map()) — broken
This single comprehensive patch applies all needed changes atomically:
- get_fd returns Option<RawFd> with full error handling
- Daemon.write_pipe: Option<PipeWriter>
- Daemon::new uses .map(|fd| unsafe { from_raw_fd(fd) })
- Daemon::ready handles Option
- SchemeDaemon.write_pipe: Option<PipeWriter>
- SchemeDaemon::new uses same closure pattern
- ready_with_fd handles Option
Replaces: P0-daemon-init-notify-graceful, P0-daemon-fix-init-notify-unwrap,
P0-daemon-silence-init-notify
100 lines
3.5 KiB
Diff
100 lines
3.5 KiB
Diff
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,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 = std::env::var(var).unwrap().parse().unwrap();
|
|
+unsafe fn get_fd(var: &str) -> Option<RawFd> {
|
|
+ let value = match std::env::var(var) {
|
|
+ Ok(value) => value,
|
|
+ Err(_) => {
|
|
+ let exe = std::env::args()
|
|
+ .next()
|
|
+ .unwrap_or_else(|| "daemon".to_string());
|
|
+ eprintln!("daemon: {var} not set for {exe}; readiness notification disabled");
|
|
+ return None;
|
|
+ }
|
|
+ };
|
|
+ let fd: RawFd = match value.parse() {
|
|
+ Ok(fd) => fd,
|
|
+ Err(err) => {
|
|
+ let exe = std::env::args()
|
|
+ .next()
|
|
+ .unwrap_or_else(|| "daemon".to_string());
|
|
+ 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 {
|
|
- panic!(
|
|
+ eprintln!(
|
|
"daemon: failed to set CLOEXEC flag for {var} fd: {}",
|
|
io::Error::last_os_error()
|
|
);
|
|
+ return None;
|
|
}
|
|
- fd
|
|
+ Some(fd)
|
|
}
|
|
|
|
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 {
|
|
- write_pipe: PipeWriter,
|
|
+ write_pipe: Option<PipeWriter>,
|
|
}
|
|
|
|
impl Daemon {
|
|
/// 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 = 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) {
|
|
- self.write_pipe.write_all(&[0]).unwrap();
|
|
+ if let Some(write_pipe) = self.write_pipe.as_mut() {
|
|
+ write_pipe.write_all(&[0]).unwrap();
|
|
+ }
|
|
}
|
|
|
|
/// 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 {
|
|
- write_pipe: PipeWriter,
|
|
+ write_pipe: Option<PipeWriter>,
|
|
}
|
|
|
|
impl SchemeDaemon {
|
|
/// 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 = 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<()> {
|
|
+ let write_pipe = match self.write_pipe {
|
|
+ Some(pipe) => pipe,
|
|
+ None => return Ok(()),
|
|
+ };
|
|
syscall::call_wo(
|
|
- self.write_pipe.as_raw_fd() as usize,
|
|
+ write_pipe.as_raw_fd() as usize,
|
|
&cap_fd.into_raw().to_ne_bytes(),
|
|
syscall::CallFlags::FD,
|
|
&[],
|