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:
+34
-23
@@ -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:?}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user