rust - 使用 Nix PTY 的子标准输入无
问题描述
我试图使用 Rust 来玩 PTY 和一些 Unix 概念。我最终得到了以下代码,不幸的是我无法使其工作。我真的很难找出标准输入的原因。子进程的 stdout 和 stderr 最终被None
分配给 PTY 从属的文件描述符。
在 Cargo.toml 文件中,我有以下依赖项:
[dependencies]
nix = "0.17.0"
libc = "0.2"
从我已经进行的调试来看,似乎 None 选项来自于https://github.com/rust-lang/rust/blob/master/src/libstd/process中完成的 ChildStdin/ChildStdout/ChildStderr 的地图.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);
}
}
}
谢谢
解决方案
推荐阅读
- reactjs - 从 Mongodb 字符串中反应电话卡文本并且没有看到换行符
- reactjs - 无法在 React 中呈现我的数组:收到错误“预期分配或函数调用,而是看到一个表达式”
- c - 有人可以向我解释这段代码是如何工作的吗?
- r - pivot_wider 导致警告 `temp` 中的值不是唯一标识的;输出将包含 list-cols
- python - 从列表中删除索引元素
- javascript - 在 Vue 中使用带有嵌套组件的 v-model
- xamarin - HttpListner 发现
- java - Spring Boot POST 参数大小限制
- c - 可以覆盖管道吗?
- typescript - 我可以在 TypeScript 中创建一个包含基本类型的自定义类型吗?