1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use crate::{FromInner, IntoInner};
use std::ffi::CStr;
use uv::{
    uv_os_free_passwd, uv_os_get_passwd, uv_os_gethostname, uv_os_getpid, uv_os_getppid,
    uv_os_getpriority, uv_os_setpriority, uv_os_uname, uv_passwd_t, uv_utsname_t,
    UV_MAXHOSTNAMESIZE,
};

/// Cross platform representation of a pid_t.
pub type Pid = i32;

/// Data type for user information.
pub struct User {
    pub username: String,
    pub uid: Option<crate::Uid>,
    pub gid: Option<crate::Gid>,
    pub shell: Option<String>,
    pub homedir: String,
}

impl FromInner<uv_passwd_t> for User {
    fn from_inner(passwd: uv_passwd_t) -> User {
        let username = unsafe { CStr::from_ptr(passwd.username) }
            .to_string_lossy()
            .into_owned();
        let homedir = unsafe { CStr::from_ptr(passwd.homedir) }
            .to_string_lossy()
            .into_owned();
        let shell = if passwd.shell.is_null() {
            None
        } else {
            Some(
                unsafe { CStr::from_ptr(passwd.shell) }
                    .to_string_lossy()
                    .into_owned(),
            )
        };
        let uid = if passwd.uid >= 0 {
            Some(passwd.uid as _)
        } else {
            None
        };
        let gid = if passwd.gid >= 0 {
            Some(passwd.gid as _)
        } else {
            None
        };
        User {
            username,
            uid,
            gid,
            shell,
            homedir,
        }
    }
}

/// Data type for operating system name and version information.
pub struct SystemInfo {
    pub sysname: String,
    pub release: String,
    pub version: String,
    pub machine: String,
}

impl FromInner<uv_utsname_t> for SystemInfo {
    fn from_inner(uname: uv_utsname_t) -> SystemInfo {
        let sysname = unsafe { CStr::from_ptr(&uname.sysname as _) }
            .to_string_lossy()
            .into_owned();
        let release = unsafe { CStr::from_ptr(&uname.release as _) }
            .to_string_lossy()
            .into_owned();
        let version = unsafe { CStr::from_ptr(&uname.version as _) }
            .to_string_lossy()
            .into_owned();
        let machine = unsafe { CStr::from_ptr(&uname.machine as _) }
            .to_string_lossy()
            .into_owned();
        SystemInfo {
            sysname,
            release,
            version,
            machine,
        }
    }
}

/// Gets a subset of the password file entry for the current effective uid (not the real uid). The
/// populated data includes the username, euid, gid, shell, and home directory. On non-Windows
/// systems, all data comes from getpwuid_r(3). On Windows, uid, gid, and shell are all set to
/// None.
pub fn get_passwd() -> crate::Result<User> {
    let mut passwd: uv_passwd_t = unsafe { std::mem::zeroed() };
    crate::uvret(unsafe { uv_os_get_passwd(&mut passwd as _) })?;

    let result = passwd.into_inner();
    unsafe { uv_os_free_passwd(&mut passwd as _) };
    Ok(result)
}

/// Returns the hostname
pub fn gethostname() -> crate::Result<String> {
    let mut size = UV_MAXHOSTNAMESIZE as usize;
    let mut buf: Vec<std::os::raw::c_uchar> = Vec::with_capacity(size);
    crate::uvret(unsafe { uv_os_gethostname(buf.as_mut_ptr() as _, &mut size as _) }).map(|_| {
        // size is the length of the string, *not* including the null
        unsafe { buf.set_len(size + 1) };
        unsafe { CStr::from_bytes_with_nul_unchecked(&buf) }
            .to_string_lossy()
            .into_owned()
    })
}

/// Returns the current process ID.
pub fn getpid() -> Pid {
    unsafe { uv_os_getpid() as _ }
}

/// Returns the parent process ID.
pub fn getppid() -> Pid {
    unsafe { uv_os_getppid() as _ }
}

/// Retrieves the scheduling priority of the process specified by pid. The returned value of
/// priority is between -20 (high priority) and 19 (low priority).
///
/// Note: On Windows, the returned priority will equal one of the libuv_sys2::UV_PRIORITY
/// constants.
pub fn getpriority(pid: Pid) -> crate::Result<i32> {
    let mut priority = 0i32;
    crate::uvret(unsafe { uv_os_getpriority(pid as _, &mut priority as _) }).map(|_| priority)
}

/// Sets the scheduling priority of the process specified by pid. The priority value range is
/// between -20 (high priority) and 19 (low priority). The constants UV_PRIORITY_LOW,
/// UV_PRIORITY_BELOW_NORMAL, UV_PRIORITY_NORMAL, UV_PRIORITY_ABOVE_NORMAL, UV_PRIORITY_HIGH, and
/// UV_PRIORITY_HIGHEST are also provided for convenience in libuv_sys2.
///
/// Note: On Windows, this function utilizes SetPriorityClass(). The priority argument is mapped to
/// a Windows priority class. When retrieving the process priority, the result will equal one of
/// the UV_PRIORITY constants, and not necessarily the exact value of priority.
///
/// Note: On Windows, setting PRIORITY_HIGHEST will only work for elevated user, for others it will
/// be silently reduced to PRIORITY_HIGH.
pub fn setpriority(pid: Pid, priority: i32) -> crate::Result<()> {
    crate::uvret(unsafe { uv_os_setpriority(pid as _, priority as _) })
}

/// Retrieves system information in buffer. The populated data includes the operating system name,
/// release, version, and machine. On non-Windows systems, uv_os_uname() is a thin wrapper around
/// uname(2).
pub fn uname() -> crate::Result<SystemInfo> {
    let mut buf: uv_utsname_t = unsafe { std::mem::zeroed() };
    crate::uvret(unsafe { uv_os_uname(&mut buf as _) })?;
    Ok(buf.into_inner())
}