Skip to content

Commit

Permalink
implement ttyname and ttyname_r
Browse files Browse the repository at this point in the history
  • Loading branch information
doy committed Jun 19, 2020
1 parent ea099dd commit 8133e94
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -33,6 +33,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
(#[1233](https://github.com/nix-rust/nix/pull/1233))
- Added `EventFilter` bitflags for `EV_DISPATCH` and `EV_RECEIPT` on OpenBSD.
(#[1252](https://github.com/nix-rust/nix/pull/1252))
- Added `unistd::ttyname` and `unistd::ttyname_r`.
(#[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))
Expand Down
39 changes: 39 additions & 0 deletions src/unistd.rs
Expand Up @@ -2778,3 +2778,42 @@ 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)).
///
/// # Safety
///
/// `ttyname()` mutates global variables and is *not* threadsafe.
/// Mutating global variables is always considered `unsafe` by Rust and this
/// function is marked as `unsafe` to reflect that.
///
/// For a threadsafe and non-`unsafe` alternative, see `ttyname_r()`.
#[inline]
pub unsafe fn ttyname(fd: RawFd) -> Result<String> {
let buf = libc::ttyname(fd);
if buf.is_null() {
return Err(Error::Sys(Errno::last()));
}

Ok(CStr::from_ptr(buf).to_string_lossy().into_owned())
}

/// 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)).
///
/// This is the threadsafe version of `ttyname()`.
#[inline]
pub fn ttyname_r(fd: RawFd) -> Result<String> {
const PATH_MAX: usize = libc::PATH_MAX as usize;
let mut buf = [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::last()));
}

let nul = buf.iter().position(|c| *c == b'\0').unwrap();
Ok(std::string::String::from_utf8_lossy(&buf[..nul]).to_string())
}
12 changes: 12 additions & 0 deletions test/test_unistd.rs
Expand Up @@ -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;
use nix::errno::Errno;
#[cfg(not(target_os = "redox"))]
use nix::Error;
Expand Down Expand Up @@ -964,3 +966,13 @@ 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);
let name_r = ttyname_r(fd.as_raw_fd()).expect("ttyname_r failed");
let name = unsafe { ttyname(fd.as_raw_fd()) }.expect("ttyname failed");
assert_eq!(name, name_r);
}

0 comments on commit 8133e94

Please sign in to comment.