Я пытался поиграть с 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);
}
}
}
Спасибо