openssh/native_mux_impl/
child.rs

1use super::Error;
2
3use std::io;
4use std::os::unix::process::ExitStatusExt;
5use std::process::ExitStatus;
6
7use openssh_mux_client::{EstablishedSession, SessionStatus};
8
9#[derive(Debug)]
10pub(crate) struct RemoteChild {
11    established_session: EstablishedSession,
12}
13
14impl RemoteChild {
15    pub(crate) fn new(established_session: EstablishedSession) -> Self {
16        Self {
17            established_session,
18        }
19    }
20
21    pub(crate) async fn disconnect(self) -> io::Result<()> {
22        // ssh multiplex protocol does not specify any message type
23        // that can be used to kill the remote process or properly shutdown
24        // the connection.
25        //
26        // So here we just let the drop handler does its job to release
27        // underlying resources such as unix stream socket and heap memory allocated,
28        // the remote process is not killed.
29        Ok(())
30    }
31
32    pub(crate) async fn wait(self) -> Result<ExitStatus, Error> {
33        let session_status = self
34            .established_session
35            .wait()
36            .await
37            .map_err(|(err, _established_session)| err)?;
38
39        match session_status {
40            SessionStatus::TtyAllocFail(_established_session) => {
41                unreachable!("native_mux_impl never allocates a tty")
42            }
43            SessionStatus::Exited { exit_value } => {
44                if let Some(val) = exit_value {
45                    if val == 127 {
46                        Err(Error::Remote(io::Error::new(
47                            io::ErrorKind::NotFound,
48                            "remote command not found",
49                        )))
50                    } else {
51                        Ok(ExitStatusExt::from_raw((val as i32) << 8))
52                    }
53                } else {
54                    Err(Error::RemoteProcessTerminated)
55                }
56            }
57        }
58    }
59}