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
|
// master_fd => PTY
|
||||||
|
|
||||||
let handle_event = |event_id: usize| {
|
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 {
|
if event_id as RawFd == tty_fd {
|
||||||
let mut packet = [0; 4096];
|
let mut packet = [0; 4096];
|
||||||
loop {
|
loop {
|
||||||
@@ -65,10 +69,15 @@ pub fn handle(
|
|||||||
Ok(0) => return,
|
Ok(0) => return,
|
||||||
Ok(count) => count,
|
Ok(count) => count,
|
||||||
Err(ref err) if err.errno() == EAGAIN => break,
|
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])
|
if let Err(err) = redox::write(master_fd as usize, &packet[..count]) {
|
||||||
.expect("getty: failed to write master PTY");
|
eprintln!("getty: failed to write master PTY: {err}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if event_id as RawFd == master_fd {
|
} else if event_id as RawFd == master_fd {
|
||||||
let mut packet = [0; 4096];
|
let mut packet = [0; 4096];
|
||||||
@@ -77,10 +86,15 @@ pub fn handle(
|
|||||||
Ok(0) => return,
|
Ok(0) => return,
|
||||||
Ok(count) => count,
|
Ok(count) => count,
|
||||||
Err(ref err) if err.errno() == EAGAIN => break,
|
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])
|
if let Err(err) = redox::write(tty_fd as usize, &packet[1..count]) {
|
||||||
.expect("getty: failed to write to TTY");
|
eprintln!("getty: failed to write to TTY: {err}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if packet[0] & 1 == 1 {
|
if packet[0] & 1 == 1 {
|
||||||
let _ = redox::fsync(tty_fd as usize);
|
let _ = redox::fsync(tty_fd as usize);
|
||||||
}
|
}
|
||||||
@@ -92,26 +106,36 @@ pub fn handle(
|
|||||||
handle_event(master_fd as usize);
|
handle_event(master_fd as usize);
|
||||||
|
|
||||||
'events: loop {
|
'events: loop {
|
||||||
let sys_event = event_queue
|
let sys_event = match event_queue.next() {
|
||||||
.next()
|
Some(Ok(event)) => event,
|
||||||
.expect("getty: event queue stopped")
|
Some(Err(err)) => {
|
||||||
.expect("getty: failed to read event file");
|
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);
|
handle_event(sys_event.fd);
|
||||||
|
|
||||||
match process.try_wait() {
|
match process.try_wait() {
|
||||||
Ok(status) => match status {
|
Ok(Some(_code)) => break 'events,
|
||||||
Some(_code) => break 'events,
|
Ok(None) => (),
|
||||||
None => (),
|
|
||||||
},
|
|
||||||
Err(err) => match err.kind() {
|
Err(err) => match err.kind() {
|
||||||
ErrorKind::WouldBlock => (),
|
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();
|
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) {
|
pub fn getpty(columns: u16, lines: u16) -> (RawFd, String) {
|
||||||
|
|||||||
Reference in New Issue
Block a user