openssh/native_mux_impl/
command.rs
1use super::Error;
2use super::RemoteChild;
3use super::{ChildStderr, ChildStdin, ChildStdout, Stdio};
4
5use std::borrow::Cow;
6use std::ffi::OsStr;
7use std::os::unix::ffi::OsStrExt;
8use std::path::Path;
9
10use openssh_mux_client::{Connection, NonZeroByteSlice, Session};
11
12#[derive(Debug)]
13pub(crate) struct Command {
14 cmd: Vec<u8>,
15 ctl: Box<Path>,
16 subsystem: bool,
17
18 stdin_v: Stdio,
19 stdout_v: Stdio,
20 stderr_v: Stdio,
21}
22
23impl Command {
24 pub(crate) fn new(ctl: Box<Path>, cmd: Vec<u8>, subsystem: bool) -> Self {
25 Self {
26 cmd,
27 ctl,
28 subsystem,
29
30 stdin_v: Stdio::inherit(),
31 stdout_v: Stdio::inherit(),
32 stderr_v: Stdio::inherit(),
33 }
34 }
35
36 pub(crate) fn raw_arg<S: AsRef<OsStr>>(&mut self, arg: S) {
37 self.cmd.push(b' ');
38 self.cmd.extend_from_slice(arg.as_ref().as_bytes());
39 }
40
41 pub(crate) fn stdin<T: Into<Stdio>>(&mut self, cfg: T) {
42 self.stdin_v = cfg.into();
43 }
44
45 pub(crate) fn stdout<T: Into<Stdio>>(&mut self, cfg: T) {
46 self.stdout_v = cfg.into();
47 }
48
49 pub(crate) fn stderr<T: Into<Stdio>>(&mut self, cfg: T) {
50 self.stderr_v = cfg.into();
51 }
52
53 pub(crate) async fn spawn(
54 &mut self,
55 ) -> Result<
56 (
57 RemoteChild,
58 Option<ChildStdin>,
59 Option<ChildStdout>,
60 Option<ChildStderr>,
61 ),
62 Error,
63 > {
64 let (stdin, child_stdin) = self.stdin_v.to_stdin()?;
65 let (stdout, child_stdout) = self.stdout_v.to_stdout()?;
66 let (stderr, child_stderr) = self.stderr_v.to_stderr()?;
67
68 let stdios = [
69 stdin.as_raw_fd_or_null_fd()?,
70 stdout.as_raw_fd_or_null_fd()?,
71 stderr.as_raw_fd_or_null_fd()?,
72 ];
73
74 let cmd = NonZeroByteSlice::new(&self.cmd).ok_or(Error::InvalidCommand)?;
75
76 #[cfg(feature = "tracing")]
77 tracing::debug!(cmd = String::from_utf8_lossy(cmd.into_inner()).as_ref());
78
79 let session = Session::builder()
80 .cmd(Cow::Borrowed(cmd))
81 .subsystem(self.subsystem)
82 .build();
83
84 let established_session = Connection::connect(&self.ctl)
85 .await?
86 .open_new_session(&session, &stdios)
87 .await?;
88
89 Ok((
90 RemoteChild::new(established_session),
91 child_stdin,
92 child_stdout,
93 child_stderr,
94 ))
95 }
96}