From 6ac41ee37a94dd30caceb3c915e178261b6f6680 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sun, 28 Jun 2026 04:00:50 +0300 Subject: [PATCH] daemon: tolerate BrokenPipe on ready(); i2cd: handle empty RON response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit daemon/src/lib.rs: Daemon::ready() previously called .unwrap() on the init pipe write, causing a panic with BrokenPipe when init had already closed its read end during the startup phase. Daemons like i2c-gpio-expanderd, intel-gpiod, dw-acpi-i2cd, and i2c-hidd hit this in redbear-mini boots. Now BrokenPipe is silently ignored — the daemon is operational regardless of init's readiness tracking state. drivers/usb/ucsid/src/main.rs and drivers/gpio/i2c-gpio-expanderd/src/main.rs: read_i2c_control_response() returned an empty buffer (no I2C adapters registered) and then tried ron::from_str('') which failed at 1:1 with 'Unexpected end of RON'. This produced false-positive warnings on every boot where no I2C hardware is present. Now an empty/whitespace response returns AdapterList(Vec::new()) gracefully. --- daemon/src/lib.rs | 12 +++++++++++- drivers/gpio/i2c-gpio-expanderd/src/main.rs | 6 +++++- drivers/usb/ucsid/src/main.rs | 6 +++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 9f50722141..495fa212cf 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -50,8 +50,18 @@ impl Daemon { } /// Notify the process that the daemon is ready to accept requests. + /// + /// BrokenPipe is tolerated: init may have already closed its read end + /// during the startup phase. The daemon is operational regardless of + /// init's readiness tracking state. pub fn ready(mut self) { - self.write_pipe.write_all(&[0]).unwrap(); + match self.write_pipe.write_all(&[0]) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::BrokenPipe => {} + Err(err) => { + eprintln!("daemon: failed to notify init of readiness: {err}"); + } + } } /// Executes `Command` as a child process. diff --git a/drivers/gpio/i2c-gpio-expanderd/src/main.rs b/drivers/gpio/i2c-gpio-expanderd/src/main.rs index 223ebc0106..d457d2df6d 100644 --- a/drivers/gpio/i2c-gpio-expanderd/src/main.rs +++ b/drivers/gpio/i2c-gpio-expanderd/src/main.rs @@ -429,7 +429,11 @@ fn read_i2c_control_response(file: &mut File) -> Result { .context("failed to read I2C control response")?; buffer.truncate(count); let text = std::str::from_utf8(&buffer).context("I2C control response was not UTF-8")?; - ron::from_str(text).context("failed to decode I2C control response") + let trimmed = text.trim(); + if trimmed.is_empty() { + return Ok(I2cControlResponse::AdapterList(Vec::new())); + } + ron::from_str(trimmed).context("failed to decode I2C control response") } fn eisa_id_from_integer(integer: u64) -> String { diff --git a/drivers/usb/ucsid/src/main.rs b/drivers/usb/ucsid/src/main.rs index 612f5ce2f2..d00cfbcfe1 100644 --- a/drivers/usb/ucsid/src/main.rs +++ b/drivers/usb/ucsid/src/main.rs @@ -785,7 +785,11 @@ fn read_i2c_control_response(file: &mut File) -> Result { .context("failed to read I2C control response")?; buffer.truncate(count); let text = std::str::from_utf8(&buffer).context("I2C control response was not UTF-8")?; - ron::from_str(text).context("failed to decode I2C control response") + let trimmed = text.trim(); + if trimmed.is_empty() { + return Ok(I2cControlResponse::AdapterList(Vec::new())); + } + ron::from_str(trimmed).context("failed to decode I2C control response") } fn read_symbol_id(path: &Path) -> Result> {