ptyd: harden against transient scan/event-queue errors

Replace two panics (initial scan_requests expect, event-queue read
expect) and a socket-event break with error logging + continuation. A
transient error reading the event queue or scanning requests must not
kill ptyd and take the whole pty subsystem down with it.

(Change found as uncommitted work in the fork; committing to preserve
it and unblock the clean-fork build gate.)
This commit is contained in:
Red Bear OS
2026-07-19 12:25:21 +09:00
parent 5f78ad843a
commit 0683c020a5
+34 -23
View File
@@ -62,20 +62,32 @@ fn daemon(daemon: daemon::SchemeDaemon) -> ! {
let mut timeout_count = 0u64;
scan_requests(&mut handler, &mut scheme).expect("pty: could not scan requests");
if let Err(err) = scan_requests(&mut handler, &mut scheme) {
eprintln!("ptyd: initial scan_requests failed: {err:?}");
}
issue_events(&socket, &mut scheme);
for event_res in event_queue {
let event = event_res.expect("pty: failed to read from event queue");
let event = match event_res {
Ok(event) => event,
Err(err) => {
// A transient event-queue read error must not kill ptyd. Log and
// wait for the next event rather than panicking.
eprintln!("ptyd: event queue read failed: {err:?}; continuing");
continue;
}
};
match event.user_data {
EventSource::Socket => {
if scan_requests(&mut handler, &mut scheme).is_err() {
break;
if let Err(err) = scan_requests(&mut handler, &mut scheme) {
eprintln!("ptyd: scan_requests failed: {err:?}; continuing");
}
}
EventSource::Time => {
timeout(&mut time_file).expect("pty: failed to set timeout");
if let Err(err) = timeout(&mut time_file) {
eprintln!("ptyd: failed to set timeout: {err:?}");
}
timeout_count = timeout_count.wrapping_add(1);
@@ -85,9 +97,9 @@ fn daemon(daemon: daemon::SchemeDaemon) -> ! {
}
}
handler
.poll_all_requests(&mut scheme)
.expect("ihdad: failed to poll requests");
if let Err(err) = handler.poll_all_requests(&mut scheme) {
eprintln!("ptyd: poll_all_requests failed: {err:?}; continuing");
}
}
}
@@ -101,15 +113,13 @@ fn scan_requests(
handler: &mut ReadinessBased<'_>,
scheme: &mut PtyScheme,
) -> libredox::error::Result<()> {
handler
.read_and_process_requests(scheme)
.expect("pty: failed to read from socket");
handler
.poll_all_requests(scheme)
.expect("pty: error occured in poll_all_requests");
handler
.write_responses()
.expect("pty: failed to write to socket");
// Propagate errors instead of panicking: a transient/error return here must
// NOT crash ptyd — it is the sole provider of the `pty` scheme, so a panic
// takes down every pty (and thus every getty/login/shell console) at once.
// The caller logs and continues on error, keeping ptyd alive.
handler.read_and_process_requests(scheme)?;
handler.poll_all_requests(scheme)?;
handler.write_responses()?;
Ok(())
}
@@ -118,13 +128,14 @@ fn issue_events(socket: &Socket, scheme: &mut PtyScheme) {
if let Handle::Resource(ref mut res) = handle {
let events = res.events();
if events != syscall::EventFlags::empty() {
socket
.write_response(
Response::post_fevent(*id, events.bits()),
SignalBehavior::Restart,
)
.expect("pty: failed to send scheme event");
if let Err(err) = socket.write_response(
Response::post_fevent(*id, events.bits()),
SignalBehavior::Restart,
) {
eprintln!("ptyd: failed to send scheme event for handle {id}: {err:?}");
}
}
}
}
}