Upload spectral-pty/src/unix.rs
Browse files- spectral-pty/src/unix.rs +89 -0
spectral-pty/src/unix.rs
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use libc;
|
| 2 |
+
use std::fs::File;
|
| 3 |
+
use std::io::{self, Read, Write};
|
| 4 |
+
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
|
| 5 |
+
|
| 6 |
+
use crate::PtyTrait;
|
| 7 |
+
|
| 8 |
+
pub struct Pty {
|
| 9 |
+
pub master: File,
|
| 10 |
+
pub child_pid: libc::pid_t,
|
| 11 |
+
pub shell_path: String,
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
impl Pty {
|
| 15 |
+
pub fn new(cols: u16, rows: u16, shell: Option<&str>) -> io::Result<Self> {
|
| 16 |
+
let shell_path = shell.map(|s| s.to_string()).unwrap_or_else(|| {
|
| 17 |
+
std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string())
|
| 18 |
+
});
|
| 19 |
+
let shell = shell_path.as_str();
|
| 20 |
+
|
| 21 |
+
let mut winsize = libc::winsize {
|
| 22 |
+
ws_row: rows, ws_col: cols, ws_xpixel: 0, ws_ypixel: 0,
|
| 23 |
+
};
|
| 24 |
+
|
| 25 |
+
let mut master_fd: RawFd = -1;
|
| 26 |
+
let mut slave_fd: RawFd = -1;
|
| 27 |
+
|
| 28 |
+
unsafe {
|
| 29 |
+
if libc::openpty(
|
| 30 |
+
&mut master_fd, &mut slave_fd,
|
| 31 |
+
std::ptr::null_mut(), std::ptr::null(), &mut winsize,
|
| 32 |
+
) != 0 { return Err(io::Error::last_os_error()); }
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
let child_pid = unsafe { libc::fork() };
|
| 36 |
+
if child_pid < 0 { return Err(io::Error::last_os_error()); }
|
| 37 |
+
|
| 38 |
+
if child_pid == 0 {
|
| 39 |
+
unsafe {
|
| 40 |
+
libc::close(master_fd);
|
| 41 |
+
libc::setsid();
|
| 42 |
+
libc::ioctl(slave_fd, libc::TIOCSCTTY, 0);
|
| 43 |
+
libc::dup2(slave_fd, 0);
|
| 44 |
+
libc::dup2(slave_fd, 1);
|
| 45 |
+
libc::dup2(slave_fd, 2);
|
| 46 |
+
if slave_fd > 2 { libc::close(slave_fd); }
|
| 47 |
+
let shell_c = std::ffi::CString::new(shell).unwrap();
|
| 48 |
+
let arg0_c = std::ffi::CString::new("-").unwrap();
|
| 49 |
+
libc::execvp(shell_c.as_ptr(), [arg0_c.as_ptr(), std::ptr::null()].as_ptr());
|
| 50 |
+
libc::_exit(1);
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
unsafe { libc::close(slave_fd); }
|
| 55 |
+
let master = unsafe { File::from_raw_fd(master_fd) };
|
| 56 |
+
|
| 57 |
+
Ok(Self { master, child_pid, shell_path })
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
impl PtyTrait for Pty {
|
| 62 |
+
fn resize(&mut self, cols: u16, rows: u16) -> io::Result<()> {
|
| 63 |
+
let winsize = libc::winsize {
|
| 64 |
+
ws_row: rows, ws_col: cols, ws_xpixel: 0, ws_ypixel: 0,
|
| 65 |
+
};
|
| 66 |
+
let fd = self.master.as_raw_fd();
|
| 67 |
+
unsafe {
|
| 68 |
+
if libc::ioctl(fd, libc::TIOCSWINSZ, &winsize) != 0 {
|
| 69 |
+
return Err(io::Error::last_os_error());
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
Ok(())
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
fn pid(&self) -> Option<u32> { Some(self.child_pid as u32) }
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
impl Read for Pty {
|
| 79 |
+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.master.read(buf) }
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
impl Write for Pty {
|
| 83 |
+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.master.write(buf) }
|
| 84 |
+
fn flush(&mut self) -> io::Result<()> { self.master.flush() }
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
impl Drop for Pty {
|
| 88 |
+
fn drop(&mut self) { unsafe { libc::kill(self.child_pid, libc::SIGHUP); } }
|
| 89 |
+
}
|