daemonize 0.0.2

Library to enable your code run as a daemon process on Unix-like systems.
Documentation
extern crate libc;

use std::ffi::{CString};

#[repr(C)]
#[allow(dead_code)]
struct passwd {
    pw_name:   *const libc::c_char,
    pw_passwd: *const libc::c_char,
    pw_uid:    libc::uid_t,
    pw_gid:    libc::gid_t,
    pw_gecos:  *const libc::c_char,
    pw_dir:    *const libc::c_char,
    pw_shell:  *const libc::c_char,
}

#[repr(C)]
#[allow(dead_code)]
struct group {
    gr_name:   *const libc::c_char,
    gr_passwd: *const libc::c_char,
    gr_gid:    libc::gid_t,
    gr_mem:    *const *const libc::c_char,
}

extern {
    fn getgrnam(name: *const libc::c_char) -> *const group;
    fn getpwnam(name: *const libc::c_char) -> *const passwd;
    pub fn umask(mask: libc::mode_t) -> libc::mode_t;
    pub fn flock(fd: libc::c_int, operation: libc::c_int) -> libc::c_int;
}

#[cfg(target_os = "linux")]
unsafe fn errno_location() -> *const libc::c_int {
    extern { fn __errno_location() -> *const libc::c_int; }
    __errno_location()
}
#[cfg(target_os = "macos")]
unsafe fn errno_location() -> *const libc::c_int {
    extern { fn __error() -> *const libc::c_int; }
    __error()
}

pub unsafe fn errno() -> libc::c_int {
    *errno_location()
}

pub unsafe fn get_gid_by_name(name: &CString) -> Option<libc::gid_t> {
    let ptr = getgrnam(name.as_ptr() as *const libc::c_char);
    if ptr.is_null() {
        None
    } else {
        let ref s = *ptr;
        Some(s.gr_gid)
    }
}

pub unsafe fn get_uid_by_name(name: &CString) -> Option<libc::uid_t> {
    let ptr = getpwnam(name.as_ptr() as *const libc::c_char);
    if ptr.is_null() {
        None
    } else {
        let ref s = *ptr;
        Some(s.pw_uid)
    }
}

#[cfg(target_os = "linux")]
#[allow(dead_code)]
unsafe fn nobody_uid_gid() -> libc::uid_t {
    (u16::max_value() - 1) as libc::uid_t
}

#[cfg(target_os = "macos")]
#[allow(dead_code)]
unsafe fn nobody_uid_gid() -> libc::uid_t {
    (u32::max_value() - 1) as libc::uid_t
}

#[test]
fn test_get_gid_by_name() {
    let group_name = ::std::ffi::CString::new(match ::std::fs::metadata("/etc/debian_version") {
        Ok(_) => "nogroup",
        Err(_) => "nobody",
    }).unwrap();
    unsafe {
        let gid = get_gid_by_name(&group_name);
        assert_eq!(gid, Some(nobody_uid_gid()))
    }
}

#[test]
fn test_get_uid_by_name() {
    let user_name = ::std::ffi::CString::new("nobody").unwrap();
    unsafe {
        let uid = get_uid_by_name(&user_name);
        assert_eq!(uid, Some(nobody_uid_gid()))
    }
}