diff --git a/src/channel.rs b/src/channel.rs index f4ce52d..73139bb 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,10 +1,11 @@ use std::fs::{File, OpenOptions}; use std::io::{self, Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; use std::os::unix::process::CommandExt; use std::path::PathBuf; use std::process::{self, Stdio}; -use sys::{before_exec, getpty}; +use std::thread::{self, JoinHandle}; +use sys; pub type ChannelId = u32; @@ -15,20 +16,20 @@ pub struct Channel { process: Option, pty: Option<(RawFd, PathBuf)>, master: Option, - stdio: Option<(File, File, File)>, window_size: u32, peer_window_size: u32, max_packet_size: u32, + read_thread: Option>, } #[derive(Debug)] pub enum ChannelRequest { Pty { term: String, - char_width: u32, - row_height: u32, - pixel_width: u32, - pixel_height: u32, + chars: u16, + rows: u16, + pixel_width: u16, + pixel_height: u16, modes: Vec, }, Shell, @@ -45,19 +46,21 @@ impl Channel { process: None, master: None, pty: None, - stdio: None, window_size: peer_window_size, peer_window_size: peer_window_size, max_packet_size: max_packet_size, + read_thread: None, } } pub fn id(&self) -> ChannelId { self.id } + pub fn window_size(&self) -> u32 { self.window_size } + pub fn max_packet_size(&self) -> u32 { self.max_packet_size } @@ -65,41 +68,75 @@ impl Channel { pub fn request(&mut self, request: ChannelRequest) { match request { - ChannelRequest::Pty { .. } => { - let (master_fd, tty_path) = getpty(); + ChannelRequest::Pty { + chars, + rows, + pixel_width, + pixel_height, + .. + } => { + let (master_fd, tty_path) = sys::getpty(); - let stdin = OpenOptions::new() - .read(true) - .write(true) - .open(&tty_path) - .unwrap(); + sys::set_winsize( + master_fd, + chars, + rows, + pixel_width, + pixel_height, + ); - let stdout = OpenOptions::new() - .read(true) - .write(true) - .open(&tty_path) - .unwrap(); + self.read_thread = Some(thread::spawn(move || { + use libc::dup; + let master2 = unsafe { dup(master_fd) }; - let stderr = OpenOptions::new() - .read(true) - .write(true) - .open(&tty_path) - .unwrap(); + println!("dup result: {}", dup as u32); + let mut master = unsafe { File::from_raw_fd(master2) }; + loop { + use std::str::from_utf8_unchecked; + let mut buf = [0; 4096]; + let count = master.read(&mut buf).unwrap(); + if count == 0 { + break; + } + println!("Read: {}", unsafe { + from_utf8_unchecked(&buf[0..count]) + }); + } - self.stdio = Some((stdin, stdout, stderr)); + println!("Quitting read thread."); + })); + + self.pty = Some((master_fd, tty_path)); self.master = Some(unsafe { File::from_raw_fd(master_fd) }); } ChannelRequest::Shell => { - if let Some((ref stdin, ref stdout, ref stderr)) = self.stdio { + if let Some(&(_, ref tty_path)) = self.pty.as_ref() { + let stdin = OpenOptions::new() + .read(true) + .write(true) + .open(&tty_path) + .unwrap() + .into_raw_fd(); + + let stdout = OpenOptions::new() + .read(true) + .write(true) + .open(&tty_path) + .unwrap() + .into_raw_fd(); + + let stderr = OpenOptions::new() + .read(true) + .write(true) + .open(&tty_path) + .unwrap() + .into_raw_fd(); + process::Command::new("login") - .stdin(unsafe { Stdio::from_raw_fd(stdin.as_raw_fd()) }) - .stdout( - unsafe { Stdio::from_raw_fd(stdout.as_raw_fd()) }, - ) - .stderr( - unsafe { Stdio::from_raw_fd(stderr.as_raw_fd()) }, - ) - .before_exec(|| before_exec()) + .stdin(unsafe { Stdio::from_raw_fd(stdin) }) + .stdout(unsafe { Stdio::from_raw_fd(stdout) }) + .stderr(unsafe { Stdio::from_raw_fd(stderr) }) + .before_exec(|| sys::before_exec()) .spawn() .unwrap(); } @@ -117,15 +154,4 @@ impl Channel { Ok(()) } } - - pub fn read(&mut self) -> io::Result> { - if let Some(ref mut master) = self.master { - let mut buf = [0; 4096]; - let count = master.read(&mut buf)?; - Ok(buf[0..count].to_vec()) - } - else { - Ok(b"".to_vec()) - } - } } diff --git a/src/sys/redox.rs b/src/sys/redox.rs index 247f52e..1b0ef5b 100644 --- a/src/sys/redox.rs +++ b/src/sys/redox.rs @@ -11,13 +11,13 @@ pub fn fork() -> usize { unsafe { syscall::clone(0).unwrap() } } +pub fn set_winsize(fd: RawFd, row: u16, col: u16, xpixel: u16, ypixel: u16) {} + pub fn getpty() -> (RawFd, PathBuf) { use syscall; - let master = syscall::open( - "pty:", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ).unwrap(); + let master = syscall::open("pty:", syscall::O_RDWR | syscall::O_CREAT) + .unwrap(); let mut buf: [u8; 4096] = [0; 4096]; diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 9015402..79b7946 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -12,16 +12,28 @@ pub fn before_exec() -> Result<()> { } pub fn fork() -> usize { - extern crate libc; + use libc; unsafe { libc::fork() as usize } } +pub fn set_winsize(fd: RawFd, row: u16, col: u16, xpixel: u16, ypixel: u16) { + use libc; + unsafe { + let size = libc::winsize { + ws_row: row, + ws_col: col, + ws_xpixel: xpixel, + ws_ypixel: ypixel, + }; + libc::ioctl(fd, libc::TIOCSWINSZ, &size as *const libc::winsize); + } +} + pub fn getpty() -> (RawFd, PathBuf) { use libc; use std::ffi::CStr; use std::fs::OpenOptions; use std::io::Error; - use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::IntoRawFd; const TIOCPKT: libc::c_ulong = 0x5420; @@ -35,7 +47,6 @@ pub fn getpty() -> (RawFd, PathBuf) { let master_fd = OpenOptions::new() .read(true) .write(true) - .custom_flags(libc::O_NONBLOCK) .open("/dev/ptmx") .unwrap() .into_raw_fd();