summaryrefslogtreecommitdiffstats
path: root/vendor/sysinfo-0.26.7/src/apple/users.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sysinfo-0.26.7/src/apple/users.rs')
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/users.rs178
1 files changed, 178 insertions, 0 deletions
diff --git a/vendor/sysinfo-0.26.7/src/apple/users.rs b/vendor/sysinfo-0.26.7/src/apple/users.rs
new file mode 100644
index 000000000..690aceee1
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/users.rs
@@ -0,0 +1,178 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::{
+ common::{Gid, Uid},
+ User,
+};
+
+use crate::sys::utils;
+use libc::{c_char, endpwent, getgrgid, getgrouplist, getpwent, gid_t, setpwent, strlen};
+
+fn get_user_groups(name: *const c_char, group_id: gid_t) -> Vec<String> {
+ let mut add = 0;
+
+ loop {
+ let mut nb_groups = 256 + add;
+ let mut groups = Vec::with_capacity(nb_groups as _);
+ unsafe {
+ if getgrouplist(name, group_id as _, groups.as_mut_ptr(), &mut nb_groups) == -1 {
+ add += 100;
+ continue;
+ }
+ groups.set_len(nb_groups as _);
+ return groups
+ .into_iter()
+ .filter_map(|g| {
+ let group = getgrgid(g as _);
+ if group.is_null() {
+ return None;
+ }
+ utils::cstr_to_rust((*group).gr_name)
+ })
+ .collect();
+ }
+ }
+}
+
+fn endswith(s1: *const c_char, s2: &[u8]) -> bool {
+ if s1.is_null() {
+ return false;
+ }
+ unsafe {
+ let mut len = strlen(s1) as isize - 1;
+ let mut i = s2.len() as isize - 1;
+ while len >= 0 && i >= 0 && *s1.offset(len) == s2[i as usize] as _ {
+ i -= 1;
+ len -= 1;
+ }
+ i == -1
+ }
+}
+
+fn users_list<F>(filter: F) -> Vec<User>
+where
+ F: Fn(*const c_char, u32) -> bool,
+{
+ let mut users = Vec::new();
+
+ unsafe {
+ setpwent();
+ loop {
+ let pw = getpwent();
+ if pw.is_null() {
+ break;
+ }
+
+ if !filter((*pw).pw_shell, (*pw).pw_uid) {
+ // This is not a "real" or "local" user.
+ continue;
+ }
+
+ let groups = get_user_groups((*pw).pw_name, (*pw).pw_gid);
+ let uid = (*pw).pw_uid;
+ let gid = (*pw).pw_gid;
+ if let Some(name) = utils::cstr_to_rust((*pw).pw_name) {
+ users.push(User {
+ uid: Uid(uid),
+ gid: Gid(gid),
+ name,
+ groups,
+ });
+ }
+ }
+ endpwent();
+ }
+ users.sort_unstable_by(|x, y| x.name.partial_cmp(&y.name).unwrap());
+ users.dedup_by(|a, b| a.name == b.name);
+ users
+}
+
+pub(crate) fn get_users_list() -> Vec<User> {
+ users_list(|shell, uid| {
+ !endswith(shell, b"/false") && !endswith(shell, b"/uucico") && uid < 65536
+ })
+}
+
+// This was the OSX-based solution. It provides enough information, but what a mess!
+// pub fn get_users_list() -> Vec<User> {
+// let mut users = Vec::new();
+// let node_name = b"/Local/Default\0";
+
+// unsafe {
+// let node_name = ffi::CFStringCreateWithCStringNoCopy(
+// std::ptr::null_mut(),
+// node_name.as_ptr() as *const c_char,
+// ffi::kCFStringEncodingMacRoman,
+// ffi::kCFAllocatorNull as *mut c_void,
+// );
+// let node_ref = ffi::ODNodeCreateWithName(
+// ffi::kCFAllocatorDefault,
+// ffi::kODSessionDefault,
+// node_name,
+// std::ptr::null_mut(),
+// );
+// let query = ffi::ODQueryCreateWithNode(
+// ffi::kCFAllocatorDefault,
+// node_ref,
+// ffi::kODRecordTypeUsers as _, // kODRecordTypeGroups
+// std::ptr::null(),
+// 0,
+// std::ptr::null(),
+// std::ptr::null(),
+// 0,
+// std::ptr::null_mut(),
+// );
+// if query.is_null() {
+// return users;
+// }
+// let results = ffi::ODQueryCopyResults(
+// query,
+// false as _,
+// std::ptr::null_mut(),
+// );
+// let len = ffi::CFArrayGetCount(results);
+// for i in 0..len {
+// let name = match get_user_name(ffi::CFArrayGetValueAtIndex(results, i)) {
+// Some(n) => n,
+// None => continue,
+// };
+// let groups = get_user_groups(&name);
+// users.push(User { name });
+// }
+
+// ffi::CFRelease(results as *const c_void);
+// ffi::CFRelease(query as *const c_void);
+// ffi::CFRelease(node_ref as *const c_void);
+// ffi::CFRelease(node_name as *const c_void);
+// }
+// users.sort_unstable_by(|x, y| x.name.partial_cmp(&y.name).unwrap());
+// return users;
+// }
+
+// fn get_user_name(result: *const c_void) -> Option<String> {
+// let user_name = ffi::ODRecordGetRecordName(result as _);
+// let ptr = ffi::CFStringGetCharactersPtr(user_name);
+// String::from_utf16(&if ptr.is_null() {
+// let len = ffi::CFStringGetLength(user_name); // It returns the len in UTF-16 code pairs.
+// if len == 0 {
+// continue;
+// }
+// let mut v = Vec::with_capacity(len as _);
+// for x in 0..len {
+// v.push(ffi::CFStringGetCharacterAtIndex(user_name, x));
+// }
+// v
+// } else {
+// let mut v: Vec<u16> = Vec::new();
+// let mut x = 0;
+// loop {
+// let letter = *ptr.offset(x);
+// if letter == 0 {
+// break;
+// }
+// v.push(letter);
+// x += 1;
+// }
+// v
+// }.ok()
+// }