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
use std::ptr;
use std::io;
use std::io::ErrorKind::InvalidData;
use super::ffi::{c_char, pid_t};
use ffi::login as ffi;
use super::Result;
use mbox::MString;

/// Systemd slice and unit types
pub enum UnitType {
    /// User slice, service or scope unit
    UserUnit,
    /// System slice, service or scope unit
    SystemUnit,
}

/// Determines the systemd unit (i.e. service or scope unit) identifier of a process.
///
/// Specific processes can be optionally targeted via their PID. When no PID is
/// specified, operation is executed for the calling process.
/// This method can be used to retrieve either a system or an user unit identifier.
pub fn get_unit(unit_type: UnitType, pid: Option<pid_t>) -> Result<String> {
    let mut c_unit_name: *mut c_char = ptr::null_mut();
    let p: pid_t = pid.unwrap_or(0);
    match unit_type {
        UnitType::UserUnit => sd_try!(ffi::sd_pid_get_user_unit(p, &mut c_unit_name)),
        UnitType::SystemUnit => sd_try!(ffi::sd_pid_get_unit(p, &mut c_unit_name))
    };
    let unit_name = unsafe { MString::from_raw(c_unit_name) };
    let unit_name = try!(unit_name.or(Err(io::Error::new(InvalidData, "Invalid unit name"))));
    Ok(unit_name.to_string())
}

/// Determines the slice (either in system or user session) of a process.
///
/// Specific processes can be optionally targeted via their PID. When no PID is
/// specified, operation is executed for the calling process.
/// This method can be used to retrieve either a system or an user slice identifier.
pub fn get_slice(slice_type: UnitType, pid: Option<pid_t>) -> Result<String> {
    let mut c_slice_name: *mut c_char = ptr::null_mut();
    let p: pid_t = pid.unwrap_or(0);
    match slice_type {
        UnitType::UserUnit => sd_try!(ffi::sd_pid_get_user_slice(p, &mut c_slice_name)),
        UnitType::SystemUnit => sd_try!(ffi::sd_pid_get_slice(p, &mut c_slice_name))
    };
    let slice_id = unsafe { MString::from_raw(c_slice_name) };
    let slice_id = try!(slice_id.or(Err(io::Error::new(InvalidData, "Invalid slice id"))));
    Ok(slice_id.to_string())
}

/// Determines the machine name of a process.
///
/// Specific processes can be optionally targeted via their PID. When no PID is
/// specified, operation is executed for the calling process.
/// This method can be used to retrieve the machine name of processes running
/// inside a VM or a container.
pub fn get_machine_name(pid: Option<pid_t>) -> Result<String> {
    let mut c_machine_name: *mut c_char = ptr::null_mut();
    let p: pid_t = pid.unwrap_or(0);
    sd_try!(ffi::sd_pid_get_machine_name(p, &mut c_machine_name));
    let machine_id = unsafe { MString::from_raw(c_machine_name) };
    let machine_id = try!(machine_id.or(Err(io::Error::new(InvalidData, "Invalid machine id"))));
    Ok(machine_id.to_string())
}

/// Determines the control group path of a process.
///
/// Specific processes can be optionally targeted via their PID. When no PID is
/// specified, operation is executed for the calling process.
/// This method can be used to retrieve the control group path of a specific
/// process, relative to the root of the hierarchy. It returns the path without
/// trailing slash, except for processes located in the root control group,
/// where "/" is returned.
pub fn get_cgroup(pid: Option<pid_t>) -> Result<String> {
    let mut c_cgroup: *mut c_char = ptr::null_mut();
    let p: pid_t = pid.unwrap_or(0);
    sd_try!(ffi::sd_pid_get_cgroup(p, &mut c_cgroup));
    let cg = unsafe { MString::from_raw(c_cgroup) };
    let cg = try!(cg.or(Err(io::Error::new(InvalidData, "Invalid cgroup"))));
    Ok(cg.to_string())
}

/// Determines the session identifier of a process.
///
/// Specific processes can be optionally targeted via their PID. When no PID is
/// specified, operation is executed for the calling process.
/// This method can be used to retrieve a session identifier.
pub fn get_session(pid: Option<pid_t>) -> Result<String> {
    let mut c_session: *mut c_char = ptr::null_mut();
    let p: pid_t = pid.unwrap_or(0);
    sd_try!(ffi::sd_pid_get_session(p, &mut c_session));
    let ss = unsafe { MString::from_raw(c_session) };
    let ss = try!(ss.or(Err(io::Error::new(InvalidData, "Invalid session"))));
    Ok(ss.to_string())
}

/// Determines the owner uid of a process.
///
/// Specific processes can be optionally targeted via their PID. When no PID is
/// specified, operation is executed for the calling process.
/// This method can be used to retrieve an owner uid.
pub fn get_owner_uid(pid: Option<pid_t>) -> Result<pid_t> {
    let mut c_owner_uid: u32 = 0u32;
    let p: pid_t = pid.unwrap_or(0);
    sd_try!(ffi::sd_pid_get_owner_uid(p, &mut c_owner_uid));
    Ok(c_owner_uid as pid_t)
}