Skip to content

Commit c59e711

Browse files
committed
Add openpty()
1 parent 7b5dd78 commit c59e711

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1010
([#582](https://github.com/nix-rust/nix/pull/582)
1111
- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}`
1212
([#551](https://github.com/nix-rust/nix/pull/551))
13+
- Added `nix::ptr::openpty`
14+
([#456](https://github.com/nix-rust/nix/pull/456))
1315

1416
### Changed
1517
- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe.

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub mod mount;
4444
#[cfg(target_os = "linux")]
4545
pub mod mqueue;
4646

47+
pub mod pty;
48+
4749
#[cfg(any(target_os = "linux", target_os = "macos"))]
4850
pub mod poll;
4951

src/pty.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use libc;
2+
3+
use {Errno, Result};
4+
use std::os::unix::io::RawFd;
5+
6+
use sys::termios::Termios;
7+
8+
pub use libc::pid_t as SessionId;
9+
pub use libc::winsize as Winsize;
10+
11+
pub struct OpenptyResult {
12+
pub master: RawFd,
13+
pub slave: RawFd,
14+
}
15+
16+
/// Create a new pseudoterminal, returning the slave and master file descriptors
17+
/// in `OpenptyResult`
18+
/// (see [openpty](http://man7.org/linux/man-pages/man3/openpty.3.html)).
19+
///
20+
/// If `winsize` is not `None`, the window size of the slave will be set to
21+
/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
22+
/// terminal settings of the slave will be set to the values in `termios`.
23+
#[inline]
24+
pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> {
25+
use std::ptr;
26+
27+
let mut slave: libc::c_int = -1;
28+
let mut master: libc::c_int = -1;
29+
let c_termios = match termios.into() {
30+
Some(termios) => termios as *const Termios,
31+
None => ptr::null() as *const Termios,
32+
};
33+
let c_winsize = match winsize.into() {
34+
Some(ws) => ws as *const Winsize,
35+
None => ptr::null() as *const Winsize,
36+
};
37+
let ret = unsafe {
38+
libc::openpty(
39+
&mut master as *mut libc::c_int,
40+
&mut slave as *mut libc::c_int,
41+
ptr::null_mut(),
42+
c_termios as *mut libc::termios,
43+
c_winsize as *mut Winsize)
44+
};
45+
46+
let _ = try!(Errno::result(ret));
47+
48+
Ok(OpenptyResult {
49+
master: master,
50+
slave: slave,
51+
})
52+
}

test/test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod sys;
1313
mod test_fcntl;
1414
mod test_net;
1515
mod test_nix_path;
16+
mod test_pty;
1617
#[cfg(any(target_os = "linux", target_os = "android"))]
1718
mod test_sendfile;
1819
mod test_stat;

test/test_pty.rs

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use libc;
2+
3+
use nix::pty::openpty;
4+
use nix::sys::termios::*;
5+
use nix::unistd::{read, write, close};
6+
7+
#[test]
8+
fn test_openpty() {
9+
// TODO: figure out the right termios settings to pass in here
10+
println!("foo");
11+
let mut termios = tcgetattr(libc::STDIN_FILENO).unwrap();
12+
println!("bar");
13+
termios.c_oflag &= !ONLCR;
14+
15+
let pty = openpty(None, &termios).unwrap();
16+
assert!(pty.master > 0); // must be valid file descriptors
17+
assert!(pty.slave > 0);
18+
19+
// writing to one should be readable on the other one
20+
let string = "foofoofoo\n";
21+
let mut buf = [0u8; 16];
22+
write(pty.master, string.as_bytes()).unwrap();
23+
let len = read(pty.slave, &mut buf).unwrap();
24+
25+
assert_eq!(len, string.len());
26+
assert_eq!(&buf[0..len], string.as_bytes());
27+
28+
// read the echo as well
29+
let echoed_string = "foofoofoo\n";
30+
let len = read(pty.master, &mut buf).unwrap();
31+
assert_eq!(len, echoed_string.len());
32+
assert_eq!(&buf[0..len], echoed_string.as_bytes());
33+
34+
let string2 = "barbarbarbar\n";
35+
let echoed_string2 = "barbarbarbar\n";
36+
write(pty.slave, string2.as_bytes()).unwrap();
37+
let len = read(pty.master, &mut buf).unwrap();
38+
39+
assert_eq!(len, echoed_string2.len());
40+
assert_eq!(&buf[0..len], echoed_string2.as_bytes());
41+
42+
close(pty.master).unwrap();
43+
close(pty.slave).unwrap();
44+
}

0 commit comments

Comments
 (0)