Child Stdin Нет, используя Nix PTY - PullRequest
0 голосов
/ 11 апреля 2020

Я пытался поиграть с PTY и какой-нибудь концепцией Unix, используя Rust. Я закончил со следующим кодом, к сожалению, я не могу заставить его работать. Я действительно изо всех сил, чтобы выяснить, почему stdin. stdout и stderr дочернего процесса в конечном итоге становятся None при назначении дескриптору файла ведомого устройства PTY.

В файле Car go .toml у меня есть следующие зависимости:

[dependencies]
nix = "0.17.0"
libc = "0.2"

Из отладки, которую я уже сделал, кажется, что опция None исходит от карты ChildStdin / ChildStdout / ChildStderr, сделанной в https://github.com/rust-lang/rust/blob/master/src/libstd/process.rs#L195.

Я Я не уверен, что это проблема Rust, и, возможно, я понимаю, как работает PTY, но я написал такой же код (насколько это возможно) в C, и он ведет себя как ожидалось.

Не могли бы вы помочь? мне понять, что не так

use nix::Error;
use std::path::Path;
use std::os::unix::{
    io::{AsRawFd, FromRawFd, RawFd}
};
use nix::sys::stat::Mode;
use nix::fcntl::{OFlag, open};
use std::process::{Command, Stdio};
use std::os::unix::process::CommandExt;
use nix::pty::{PtyMaster, grantpt, posix_openpt, ptsname, unlockpt};
use libc::{self, winsize};

#[macro_use]
extern crate nix;
struct Pty {
    master: PtyMaster,
    slave: RawFd
}

fn construct_internal_pty() -> Result<Pty, Error> {
    ioctl_write_ptr_bad!(pty_io_size, nix::libc::TIOCSWINSZ, winsize);
    let master_fd = posix_openpt(OFlag::O_RDWR | OFlag::O_NOCTTY)?;

    grantpt(&master_fd)?;
    unlockpt(&master_fd)?;

    let slave_name = unsafe { ptsname(&master_fd) }?;
    let slave_fd = open(
        Path::new(&slave_name),
        OFlag::O_RDWR | OFlag::O_NOCTTY,
        Mode::empty())?;

    Ok(Pty {
        master: master_fd,
        slave: slave_fd
    })
}

fn main() -> () {
    let pty = construct_internal_pty().expect("Unable to construct PTY");
    let mut builder = Command::new("/bin/sh");

    let slave = pty.slave;
    let master = pty.master.as_raw_fd();

    builder.env("LOGNAME", "ex0ns");
    builder.env("USER", "ex0ns");
    builder.env("SHELL", "/bin/sh");
    builder.env("HOME", "/home/ex0ns");

    builder.current_dir("/home/ex0ns");
    // This is not working.... The resulting fd is None
    builder.stdin(unsafe { Stdio::from_raw_fd(slave) });
    builder.stderr(unsafe { Stdio::from_raw_fd(slave) });
    builder.stdout(unsafe { Stdio::from_raw_fd(slave) });

    unsafe {
        builder.pre_exec(move || {
            libc::setsid();

            libc::close(slave);
            libc::close(master);

            libc::signal(libc::SIGCHLD, libc::SIG_DFL);
            libc::signal(libc::SIGHUP, libc::SIG_DFL);
            libc::signal(libc::SIGINT, libc::SIG_DFL);
            libc::signal(libc::SIGQUIT, libc::SIG_DFL);
            libc::signal(libc::SIGTERM, libc::SIG_DFL);
            libc::signal(libc::SIGALRM, libc::SIG_DFL);

            Ok(())
        });
    }

    match builder.spawn() {
        Ok(child) => {
            println!("{:?}", child);
            println!("{:?}", slave);
            assert_eq!(child.stdin.is_none(), false);

            unsafe { libc::close(slave) }; // close PTY ?
        }
        Err(error) => {
            println!("Unable to spawn child process {}", error);
            ::std::process::exit(1);
        }
    }

}

Спасибо

...