daemon: tolerate BrokenPipe on ready(); i2cd: handle empty RON response

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.
This commit is contained in:
Red Bear OS
2026-06-28 04:00:50 +03:00
parent 4c798ac045
commit 6ac41ee37a
3 changed files with 21 additions and 3 deletions
+11 -1
View File
@@ -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.
+5 -1
View File
@@ -429,7 +429,11 @@ fn read_i2c_control_response(file: &mut File) -> Result<I2cControlResponse> {
.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 {
+5 -1
View File
@@ -785,7 +785,11 @@ fn read_i2c_control_response(file: &mut File) -> Result<I2cControlResponse> {
.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<Option<String>> {