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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
use ::init::init;
use ::result::{check_return, Result};

extern crate libcgroup_sys as ffi;
extern crate libc;

use std;
use std::ffi::{CStr, CString};
use std::vec::Vec;

#[derive(Debug)]
pub struct CGroupMount {
    pub controller_name: String,
    pub path: String,
}

impl From<ffi::cgroup_mount_point> for CGroupMount {
    fn from(mp: ffi::cgroup_mount_point) -> CGroupMount {
        CGroupMount {
            controller_name: unsafe {
                CStr::from_ptr(&mp.name as *const libc::c_char)
                    .to_string_lossy()
                    .into_owned()
            },
            path: unsafe {
                CStr::from_ptr(&mp.path as *const libc::c_char).to_string_lossy().into_owned()
            },
        }
    }
}

pub struct CGroupMountIter {
    handle: *const libc::c_void,
}

impl CGroupMountIter {
    pub fn new() -> CGroupMountIter {
        init();
        CGroupMountIter { handle: std::ptr::null() }
    }
}

impl Drop for CGroupMountIter {
    fn drop(&mut self) {
        unsafe {
            ffi::cgroup_get_controller_end(&self.handle);
        }
    }
}

impl Iterator for CGroupMountIter {
    type Item = Result<CGroupMount>;

    fn next(&mut self) -> Option<Result<CGroupMount>> {
        let mut mp: ffi::cgroup_mount_point = Default::default();
        let ret: i32;
        if self.handle.is_null() {
            ret = unsafe {
                ffi::cgroup_get_controller_begin(&self.handle as *const *const libc::c_void,
                                                 &mut mp)
            };
        } else {
            ret = unsafe {
                ffi::cgroup_get_controller_next(&self.handle as *const *const libc::c_void, &mut mp)
            };
        }
        if ret == ffi::ECGEOF {
            return None;
        }
        Option::Some(check_return(ret, CGroupMount::from(mp)))
    }
}

pub fn cgroup_mount_points_iter() -> CGroupMountIter {
    CGroupMountIter::new()
}

pub fn cgroup_mount_points() -> Result<Vec<CGroupMount>> {
    let mut vec = Vec::new();
    for c in cgroup_mount_points_iter() {
        let mp = match c {
            Ok(m) => m,
            Err(err) => return Err(err),
        };
        vec.push(mp);
    }
    Ok(vec)
}

#[derive(Debug)]
pub struct CGroupFileInfo {
    pub path: String,
    pub parent: String,
    pub full_path: String,
    pub depth: i16,
}

#[derive(Debug)]
pub enum CGroupFile {
    File(CGroupFileInfo),
    Dir(CGroupFileInfo),
    Other(CGroupFileInfo),
}

impl From<ffi::cgroup_file_info> for CGroupFile {
    fn from(cgf: ffi::cgroup_file_info) -> CGroupFile {
        let fi = CGroupFileInfo {
            path: unsafe {
                CStr::from_ptr(cgf.path as *const libc::c_char)
                    .to_string_lossy()
                    .into_owned()
            },
            parent: unsafe {
                CStr::from_ptr(cgf.parent as *const libc::c_char)
                    .to_string_lossy()
                    .into_owned()
            },
            full_path: unsafe {
                CStr::from_ptr(cgf.full_path as *const libc::c_char)
                    .to_string_lossy()
                    .into_owned()
            },
            depth: cgf.depth,
        };
        match cgf.file_type {
            ffi::cgroup_file_type::CGROUP_FILE_TYPE_FILE => CGroupFile::File(fi),
            ffi::cgroup_file_type::CGROUP_FILE_TYPE_DIR => CGroupFile::Dir(fi),
            ffi::cgroup_file_type::CGROUP_FILE_TYPE_OTHER => CGroupFile::Other(fi),
        }
    }
}

#[derive(Debug)]
pub struct CGroupWalkIter {
    handle: *const libc::c_void,
    base_level: libc::c_int,
    pub controller_name: String,
    pub base_path: String,
    pub depth: i32,
}

impl CGroupWalkIter {
    pub fn new<S>(controller_name: S) -> CGroupWalkIter
        where S: Into<String>
    {
        init();
        CGroupWalkIter {
            handle: std::ptr::null(),
            base_level: 0,
            controller_name: controller_name.into(),
            base_path: "".to_string(),
            depth: 0,
        }
    }

    pub fn new_with_options<S>(controller_name: S, base_path: S, depth: i32) -> CGroupWalkIter
        where S: Into<String>
    {
        init();
        CGroupWalkIter {
            handle: std::ptr::null(),
            base_level: 0,
            controller_name: controller_name.into(),
            base_path: base_path.into(),
            depth: depth,
        }
    }
}

impl Drop for CGroupWalkIter {
    fn drop(&mut self) {
        unsafe {
            ffi::cgroup_walk_tree_end(&self.handle);
        }
    }
}

impl Iterator for CGroupWalkIter {
    type Item = Result<CGroupFile>;

    fn next(&mut self) -> Option<Result<CGroupFile>> {
        let mut fi: ffi::cgroup_file_info = Default::default();
        let ret: i32;
        if self.handle.is_null() {
            ret = unsafe {
                ffi::cgroup_walk_tree_begin(CString::new(self.controller_name.clone())
                                                .unwrap()
                                                .as_ptr(),
                                            CString::new(self.base_path.clone()).unwrap().as_ptr(),
                                            self.depth,
                                            &self.handle as *const *const libc::c_void,
                                            &mut fi,
                                            &self.base_level as *const libc::c_int)
            };
        } else {
            ret = unsafe {
                ffi::cgroup_walk_tree_next(self.depth,
                                           &self.handle as *const *const libc::c_void,
                                           &mut fi,
                                           self.base_level)
            };
        }
        if ret == ffi::ECGEOF {
            return None;
        }
        Option::Some(check_return(ret, CGroupFile::from(fi)))
    }
}

pub fn cgroup_walk_tree_iter<S>(controller_name: S) -> CGroupWalkIter
    where S: Into<String>
{
    CGroupWalkIter::new(controller_name)
}