4 releases

Uses old Rust 2015

0.2.0 Sep 22, 2018
0.1.3 Oct 16, 2017
0.1.2 Oct 4, 2017
0.1.1 Oct 4, 2017

#681 in Unix APIs

MIT/Apache

11KB
78 lines

Nix ptsname_r() Shim

Build Status

Using this shim's ptsname_r() over Nix's ptsname_r() on Linux will make your application portable to macOS with regards to ptsname_r(). The ptsname_r() exposed by this crate will simply reference Nix's original ptsname_r() on Linux and use its shim on macOS. The signature of the function is identical and the behavior is identical.

Usage

Here's an example of how to convert and use this shim for an existing program using ptsname_r from Nix.

Before

Using Nix's ptsname_r(), which is not available on macOS.

extern crate nix;
use nix::fcntl::O_RDWR;
use nix::pty::{posix_openpt, ptsname_r};

fn main() {
    let master_fd = posix_openpt(O_RDWR).unwrap();
    let slave_name = ptsname_r(&master_fd).unwrap();
    println!("Slave Name was: {}", slave_name);
}

After

Using Nix ptsname_r() Shim's ptsname_r(), which makes equivalent functionality available on macOS but falls back to Nix's ptsname_r() on other platforms.

extern crate nix;
use nix::fcntl::O_RDWR;
// Remove use of Nix's ptsname_r
use nix::pty::posix_openpt;

// Add this crate and use its ptsname_r
extern crate nix_ptsname_r_shim;
use nix_ptsname_r_shim::ptsname_r;

fn main() {
    let master_fd = posix_openpt(O_RDWR).unwrap();
    let slave_name = ptsname_r(&master_fd).unwrap();
    println!("Slave Name was: {}", slave_name);
}

Background

In POSIX, ptsname() is used on a file descriptor created by posix_openpt to get the name of the slave psuedoterminal.

Unfortunately, ptsname() modifies global variables in order to return a pointer to the modified variables with the name of the slave in it. In Rust's Nix, this is interpreted as unsafe. It is also not thread-safe and can cause issues during signal handling amongst other issues. Thus, the implementation in Nix is marked as unsafe.

In response, at least on the Linux platform, there is a function called ptsname_r() which is a re-entrant and safer version of ptsname() as it writes to a buffer the caller provides. In Nix, it allocates a buffer and wraps it into an owned String to make it safe.

Unfortunately, macOS/Darwin does not include the ptsname_r() function. Alternatively, you are to use the TIOCPTYGNAME syscall with the master file descriptor and a buffer pointer as the argument. It's almost like ptsname_r() but it's different nevertheless.

It was determined that it was not in the scope of Nix to include shims such as this for platforms that do in fact have the functionality but the underlying calls are different.. Emulated functionality should be moved to an outside crate.

It's out of scope, but a shim like this is desired, as can be demonstrated with the following two examples who have implemented similar shims:

  • This example is the first I've found with this approach. The author was using it for what I'm assuming is something work related at some large hosting provider. I'm not sure what purpose the author was exactly using it for but the author had a need for ptsname_r functionality. The author was not using nix, but I can see that the author cfg gates their similar nix-like wrappers to the OS. I'm guessing that the author also wants to maintain a similar API between Linux and macOS. This version might have been the basis for the following reference.

  • My other example is doing a pexpect clone. To do a pexpect clone, the author has to open the slave terminal by its name which he had to find through ptsname_r and then assign them to the correct descriptors before calling exec in the child. Unlike the first reference, the author uses nix, but polyfills in pretty much this implementation of ptsname_r for macOS where nix/macOS falls short. Like me, and the previous example, the author also fills in the gap with a similar API for macOS that emulates the Linux version.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~1.5MB
~36K SLoC