diff options
Diffstat (limited to 'vendor/sysinfo-0.26.7/src/apple/users.rs')
-rw-r--r-- | vendor/sysinfo-0.26.7/src/apple/users.rs | 178 |
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() +// } |