getty: harden the console<->PTY bridge against transient read/write/event errors (log-and-continue instead of panic; a panic here killed the live shell's I/O)
This commit is contained in:
+40
-16
@@ -58,6 +58,10 @@ pub fn handle(
|
||||
// master_fd => PTY
|
||||
|
||||
let handle_event = |event_id: usize| {
|
||||
// The console<->PTY bridge must never panic on a transient read/write
|
||||
// error: getty runs this while the login shell is alive, so a panic here
|
||||
// kills the shell's I/O forwarding (input stops, output stops). Log and
|
||||
// stop the current forwarding cycle instead; the event loop keeps going.
|
||||
if event_id as RawFd == tty_fd {
|
||||
let mut packet = [0; 4096];
|
||||
loop {
|
||||
@@ -65,10 +69,15 @@ pub fn handle(
|
||||
Ok(0) => return,
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno() == EAGAIN => break,
|
||||
Err(_) => panic!("getty: failed to read from TTY"),
|
||||
Err(err) => {
|
||||
eprintln!("getty: failed to read from TTY: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
redox::write(master_fd as usize, &packet[..count])
|
||||
.expect("getty: failed to write master PTY");
|
||||
if let Err(err) = redox::write(master_fd as usize, &packet[..count]) {
|
||||
eprintln!("getty: failed to write master PTY: {err}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if event_id as RawFd == master_fd {
|
||||
let mut packet = [0; 4096];
|
||||
@@ -77,10 +86,15 @@ pub fn handle(
|
||||
Ok(0) => return,
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno() == EAGAIN => break,
|
||||
Err(_) => panic!("getty: failed to read from master TTY"),
|
||||
Err(err) => {
|
||||
eprintln!("getty: failed to read from master PTY: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
redox::write(tty_fd as usize, &packet[1..count])
|
||||
.expect("getty: failed to write to TTY");
|
||||
if let Err(err) = redox::write(tty_fd as usize, &packet[1..count]) {
|
||||
eprintln!("getty: failed to write to TTY: {err}");
|
||||
break;
|
||||
}
|
||||
if packet[0] & 1 == 1 {
|
||||
let _ = redox::fsync(tty_fd as usize);
|
||||
}
|
||||
@@ -92,26 +106,36 @@ pub fn handle(
|
||||
handle_event(master_fd as usize);
|
||||
|
||||
'events: loop {
|
||||
let sys_event = event_queue
|
||||
.next()
|
||||
.expect("getty: event queue stopped")
|
||||
.expect("getty: failed to read event file");
|
||||
let sys_event = match event_queue.next() {
|
||||
Some(Ok(event)) => event,
|
||||
Some(Err(err)) => {
|
||||
eprintln!("getty: failed to read event file: {err}; exiting bridge");
|
||||
break 'events;
|
||||
}
|
||||
None => {
|
||||
eprintln!("getty: event queue stopped; exiting bridge");
|
||||
break 'events;
|
||||
}
|
||||
};
|
||||
handle_event(sys_event.fd);
|
||||
|
||||
match process.try_wait() {
|
||||
Ok(status) => match status {
|
||||
Some(_code) => break 'events,
|
||||
None => (),
|
||||
},
|
||||
Ok(Some(_code)) => break 'events,
|
||||
Ok(None) => (),
|
||||
Err(err) => match err.kind() {
|
||||
ErrorKind::WouldBlock => (),
|
||||
_ => panic!("getty: failed to wait on child: {:?}", err),
|
||||
_ => {
|
||||
eprintln!("getty: failed to wait on child: {err:?}; exiting bridge");
|
||||
break 'events;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let _ = process.kill();
|
||||
process.wait().expect("getty: failed to wait on login");
|
||||
if let Err(err) = process.wait() {
|
||||
eprintln!("getty: failed to wait on login: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getpty(columns: u16, lines: u16) -> (RawFd, String) {
|
||||
|
||||
Reference in New Issue
Block a user