diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-03 23:10:41 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-03 23:10:41 +0000 |
commit | a2f40c2810ce41a9f705eb7a51020c614fea1247 (patch) | |
tree | a9cbca8fc3bda1da1c8b47469de37a28b4e3a63a | |
parent | 6f0ca030a30fd813ad74f7dc4d63d3d5538090b0 (diff) | |
parent | b5eef58e549c34f543316d3c1fd032f8475d42df (diff) | |
download | nix-a2f40c2810ce41a9f705eb7a51020c614fea1247.zip |
Merge #1259
1259: implement ttyname and ttyname_r r=asomers a=doy
this fixes #1204.
i know this at least works on linux, but i'm not super sure about other platforms - happy to add conditionals if it makes sense.
Co-authored-by: Jesse Luehrs <doy@tozt.net>
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/unistd.rs | 17 | ||||
-rw-r--r-- | test/test_unistd.rs | 47 |
3 files changed, 66 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0efdfc5d..15c7b859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). (#[1222](https://github.com/nix-rust/nix/pull/1222)) - `CpuSet` and `UnixCredentials` now implement `Default`. (#[1244](https://github.com/nix-rust/nix/pull/1244)) +- Added `unistd::ttyname` + (#[1259](https://github.com/nix-rust/nix/pull/1259)) ### Changed - Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) diff --git a/src/unistd.rs b/src/unistd.rs index f2902bb4..d53b438c 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2774,3 +2774,20 @@ impl Group { }) } } + +/// Get the name of the terminal device that is open on file descriptor fd +/// (see [`ttyname(3)`](http://man7.org/linux/man-pages/man3/ttyname.3.html)). +pub fn ttyname(fd: RawFd) -> Result<PathBuf> { + const PATH_MAX: usize = libc::PATH_MAX as usize; + let mut buf = vec![0_u8; PATH_MAX]; + let c_buf = buf.as_mut_ptr() as *mut libc::c_char; + + let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; + if ret != 0 { + return Err(Error::Sys(Errno::from_i32(ret))); + } + + let nul = buf.iter().position(|c| *c == b'\0').unwrap(); + buf.truncate(nul); + Ok(OsString::from_vec(buf).into()) +} diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 24ed2e56..da677287 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -7,6 +7,8 @@ use nix::unistd::ForkResult::*; use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction}; use nix::sys::wait::*; use nix::sys::stat::{self, Mode, SFlag}; +#[cfg(not(target_os = "redox"))] +use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname}; use nix::errno::Errno; #[cfg(not(target_os = "redox"))] use nix::Error; @@ -19,6 +21,8 @@ use std::fs::{self, File}; use std::io::Write; use std::mem; use std::os::unix::prelude::*; +#[cfg(not(target_os = "redox"))] +use std::path::Path; use tempfile::{tempdir, tempfile}; use libc::{_exit, off_t}; @@ -964,3 +968,46 @@ fn test_setfsuid() { // open the temporary file with the current thread filesystem UID fs::File::open(temp_path_2).unwrap(); } + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_ttyname() { + let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); + assert!(fd.as_raw_fd() > 0); + + // on linux, we can just call ttyname on the pty master directly, but + // apparently osx requires that ttyname is called on a slave pty (can't + // find this documented anywhere, but it seems to empirically be the case) + grantpt(&fd).expect("grantpt failed"); + unlockpt(&fd).expect("unlockpt failed"); + let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); + let fds = open( + Path::new(&sname), + OFlag::O_RDWR, + stat::Mode::empty(), + ).expect("open failed"); + assert!(fds > 0); + + let name = ttyname(fds).expect("ttyname failed"); + assert!(name.starts_with("/dev")); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_ttyname_not_pty() { + let fd = File::open("/dev/zero").unwrap(); + assert!(fd.as_raw_fd() > 0); + assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY))); +} + +#[test] +#[cfg(all(not(target_os = "redox"), not(target_env = "musl")))] +fn test_ttyname_invalid_fd() { + assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF))); +} + +#[test] +#[cfg(all(not(target_os = "redox"), target_env = "musl"))] +fn test_ttyname_invalid_fd() { + assert_eq!(ttyname(-1), Err(Error::Sys(Errno::ENOTTY))); +} |