Interacting with C structs from Rust


#1

Hi,

I’m working on a small project which needs to interact with Linux syscalls. Most of these syscalls need structures as input.

If we take the classical C approach with uname we would write:

struct utsname buf;
uname(&buf);
printf("sysname: %s\n", buf.sysname);

In rust, this is what I came up with:

extern crate libc;                                                                                                                             
use libc::utsname;                                                                                                                             
use std::ffi::CString;                                                                                                                         
                                                                                                                                               
extern {                                                                                                                                       
    pub fn uname(buf: *mut utsname) -> i32;                                                                                                    
}                                                                                                                                              
                                                                                                                                               
fn make_utsname() -> utsname {
    utsname {
        sysname: [0; 65],
        nodename: [0; 65],
        release: [0; 65],
        version: [0; 65],
        machine: [0; 65],
        domainname: [0; 65],
    }
}

fn main() {
    let mut buf: utsname = make_utsname();
    unsafe { uname(&mut buf); }

    let sysname = unsafe { CString::from_raw(buf.sysname.as_mut_ptr()) };
    println!("sysname: {}", sysname.to_str().unwrap());
}                     

While this works and gives the same result, I find having to build a 0-initialized struct a bit tedious. Am I missing something to more quickly get such as struct initialized? I looked into the default trait but cannot implement it for types defined in crates.

Any other pointers / critique of the above code would be warmly welcomed.

Thanks a lot!


#2

https://doc.rust-lang.org/stable/std/mem/fn.zeroed.html for your “make this all zeros” case.

If you used the nix crate, you could get most of this for free:

https://docs.rs/nix/0.7.0/nix/sys/utsname/fn.uname.html

That is, something like

extern crate nix;

use nix::syx::utsname;

fn main() {
    let name = utsname::uname();

    println!("sysname: {}", name.sysname());
}

(I haven’t tested this, just typed it out.)


#3

mem::zeroed() gets the code down to a good size.
The nix crate will come in very handy for what I’m doing, thanks a lot for the pointer.


#4

Bar from a small typo, (nix::sys::utsname vs nix::syx::utsname), the above code works.