如何在 Rust 中向 pty 主设备写入数据

5

我创建了一个简单的pty设置,但是我不确定在创建后如何向主或从侧写入内容。我也不确定我的设置是否正确,因为在检查时,pty的子进程的Stdin、Stdout和Stderr都为None,而不是设置为从文件描述符。是否有人能够澄清这是否正确,并且如果不正确,请问有任何建议如何解决?

use libc::{self};
use nix::pty::openpty;
use std::os::unix::io::FromRawFd;
use std::process::{Child, Command, Stdio};

#[derive(Debug)]
pub struct Pty {
    process: Child,
    fd: i32,
}

fn create_pty(process: &str) -> Pty {
    let ends = openpty(None, None).expect("openpty failed");
    let master = ends.master;
    let slave = ends.slave;

    let mut builder = Command::new(process);
    builder.stdin(unsafe { Stdio::from_raw_fd(slave) });
    builder.stdout(unsafe { Stdio::from_raw_fd(slave) });
    builder.stderr(unsafe { Stdio::from_raw_fd(slave) });

    match builder.spawn() {
        Ok(process) => {
            let pty = Pty {
                process,
                fd: master,
            };

            pty
        }
        Err(e) => {
            panic!("Failed to create pty: {}", e);
        }
    }
}

fn main() {
    let shell = "/bin/bash";

    let pty = create_pty(shell);
    println!("{:?}", pty);

    println!("{}", pty.process.id());
}
1个回答

6
这是预期的。 std::process :: Child :: stdin 等不适用于原始文件句柄(因为 Rust 不知道它们是什么,构建器没有你的 pty 的 master 端)。
您可以自己构建主控的 Rusty 文件句柄:
fn main() {
    let shell = "/bin/bash";

    let pty = create_pty(shell);
    println!("{:?}", pty);

    let mut output = unsafe { File::from_raw_fd(pty.fd) };
    write!(output, "touch /tmp/itworks\n");
    output.flush();

    std::thread::sleep_ms(1000);

    println!("{}", pty.process.id());
}

你会看到这确实创建了一个名为"/tmp/itworks"的文件。

(游乐场永久链接)


所以如果我理解正确的话,stdout、stdin和stderr注册为none的原因是因为std::process::Child类型不理解我传递到.stdin()等方法中的原始文件处理程序。鉴于这种情况,我是否最好从slave fd创建一个文件并使用它来操作? - Ethalot
1
在你的这一端,你应该使用主进程而不是从进程。因为你只会向从进程传递原始句柄(这是被生成的进程所需的),所以Child并不知道主进程。 - mcarton
“(Child).std” 为空的原因是因为在传递 “std” 句柄时,使用了新的 “Stdio” 实例,而没有使用“Stdio::piped()” 方法。我之前认为从子进程中访问 “std*” 必须使用 “Stdio::piped()” 方法。 - Sean Kelleher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接