Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable utsname on MacOS #607

Closed
arcrose opened this issue May 25, 2017 · 16 comments
Closed

Enable utsname on MacOS #607

arcrose opened this issue May 25, 2017 · 16 comments

Comments

@arcrose
Copy link

arcrose commented May 25, 2017

I'm doing a really quick experiment to try to invoke the uname function on macOS. Following the documentation, I wrote the code below.

extern crate nix;

fn main() {
    println!("Hello, world!");
    let name = nix::sys::utsname::uname();
    println!("
      sysname = {}
      nodename = {}
      release = {}
      version = {}
      machine = {}
    ", name.sysname(), name.nodename(), name.release(), name.version(), name.machine());
}

My Cargo.toml file points to version 0.8.1 of nix as a dependency. When I try to compile this program with cargo build I get the following error:

error[E0433]: failed to resolve. Could not find `utsname` in `sys`
 --> src/main.rs:5:16
  |
5 |     let name = nix::sys::utsname::uname();
  |                ^^^^^^^^^^^^^^^^^^^^^^^^ Could not find `utsname` in `sys`

I'm running this on macOS 10.12.4 with rustc 1.17.0.

@arcrose
Copy link
Author

arcrose commented May 25, 2017

I see that utsname is actually only exported for Linux and Android targets. Would it not work on macOS?

@asomers
Copy link
Member

asomers commented May 25, 2017

@zsck try it and find out. If it does, submit a PR to enable it. Include in the PR a link to the relevant man page.

@asomers asomers changed the title "Could not find utsname in sys" on macOS Enable utsname on MacOS May 25, 2017
@arcrose
Copy link
Author

arcrose commented May 25, 2017

I modified src/sys/mod.rs to export utsname on macOS like so:

#[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))]
pub mod utsname;

Now my program compiles and runs, however it terminates silently as soon as uname is called. The following println! doesn't produce output. If I do the following:

cargo run
echo $?

I can see that my program terminated with status code 1, so there's certainly some kind of error occurring.

Unfortunately I am not equipped to figure out how to resolve this issue.

@arcrose
Copy link
Author

arcrose commented May 25, 2017

Interestingly, if I modify the wrapper for uname so that it looks like so:

pub fn uname() -> UtsName {
    unsafe {
        let mut ret: UtsName = mem::uninitialized();
        let retcode = ffi::uname(&mut ret as *mut UtsName);
        println!("RETURN CODE: {}", retcode);
        ret
    }
}

Then re-run my program, I now see the following output:

Hello, world!
RETURN CODE FROM uname: 0

      sysname = Darwin
      nodename = R�
      release =
      version =
      machine =

The value of nodename appears to change every time I run my program, and sometimes there are extra whitespace (newline) characters in the value of version.

@Susurrus
Copy link
Contributor

@zsck Just wanted to point out that your documentation link is incorrect. It points to the docs for Linux (which is why that function exists). You really want to explore the docs here. Note the dropdown to select the Platform at the top of the page. This is common with multi-platform crates that have platform-specific functionality. Be sure to read the right docs!

As to the actual issue, the proper place to bring this up actually isn't here, but in libc. As you've seen, nix just provides a safe wrapper around uname, but the FFI is done by the libc crate. Please open an issue there about this (and be sure to link to this issue from there!). Once that's resolved we can expose it on MacOS if appropriate.

@arcrose
Copy link
Author

arcrose commented May 25, 2017

I am not 100% sure if this is in fact a problem with libc. I wrote the following code using libc, and it seems to work just fine.

extern crate libc;

use std::mem;

fn main() {
    println!("Getting name");
    unsafe {
        let mut name: libc::utsname = mem::uninitialized();
        let ret_code = libc::uname(&mut name as *mut libc::utsname);
        println!("RETCODE = {}", ret_code);
        print!("version = ");
        for i in 0..name.version.len() {
            print!("{}", name.version[i] as u8 as char);
        }
    }
}

The invocation of libc::uname here is inspired directly by the way it's called in nix.

@Susurrus
Copy link
Contributor

You didn't need to write code, just look at libc see and see where it's declared. What platforms do they support using it on?

@arcrose
Copy link
Author

arcrose commented May 25, 2017

I don't see anything indicating that uname wouldn't be available on both macOS and Linux. Going through their documentation into the source, it appears there are no restrictions on which platforms uname is exported for.

I don't see how it's a problem of libc's if I'm able to use uname perfectly fine via libc, but I cannot using nix.

@asomers
Copy link
Member

asomers commented May 25, 2017

There seems to be an assumption that nix::sys::utsname has the same memory layout as libc::utsname. That assumption is probably true on Linux but not OSX. That's the reason that your first experiment didn't work.

@Susurrus
Copy link
Contributor

@Somers You're probably right that the memory layout is incorrect in libc.

First off you can see that libc defines uname() for all unix platforms (@zsck it's easiest just to look through the hierarchy in the libc source like here). But utsname is defined per-platform (see here). And you can see that the OS X implements is here and that it's common among all BSDs that aren't Dragonfly.

@asomers
Copy link
Member

asomers commented May 25, 2017

@Susurrus My concern isn't that libc's definition for OSX's utsname is wrong, though that may be a problem too. My main concern is that nix's uname passes a pointer to nix's UtsName structure directly to an FFI uname function. The only way that can work is if nix's Utsname structure has the same layout as the structure that the OS's uname function expects. That's very unlikely to be true on all platforms.
https://github.com/nix-rust/nix/blob/master/src/sys/utsname.rs#L59

@Susurrus
Copy link
Contributor

Oh, man, our utsname code is completely wrong. We shouldn't have FFI definitions in our code. And really we should have a newtype and then pass that to the FFI function. As long as we specify it's repr(C) we should be fine.

@Susurrus
Copy link
Contributor

Sorry, not completely wrong, but definitely not well written.

@Susurrus
Copy link
Contributor

@zsck Would you be interested in filing a PR for this? You'd instead create a newtype for UtsName that looks like of like the PtyMaster struct I added in #556. Then defer all FFI to the libc crate. That will likely fix the issue.

@arcrose
Copy link
Author

arcrose commented May 29, 2017

I wish I could say that I would like to take care of this, but my use case for uname is very limited in scope and doesn't add a whole lot of value to the project I'm working on (for my employer).

@Susurrus
Copy link
Contributor

This should be addressed by #739. @zsck please test out that PR and let me know if it works for you.

bors bot added a commit that referenced this issue Aug 21, 2017
739: Support features across more platforms r=Susurrus

 * Exposes `utsname` on all platforms
 * Expose `signalfd` on Android

Closes #607.
@bors bors bot closed this as completed in #739 Aug 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants