You've already forked rust-users
mirror of
https://github.com/uutils/rust-users.git
synced 2026-06-10 15:48:37 -07:00
Merge branch 'polachok-all-users'
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
extern crate users;
|
||||
use users::{User, AllUsers};
|
||||
|
||||
fn main() {
|
||||
let mut users: Vec<User> = unsafe { AllUsers::new() }.collect();
|
||||
users.sort_by(|a, b| a.uid().cmp(&b.uid()));
|
||||
|
||||
for user in users {
|
||||
println!("User {} has name {}", user.uid(), user.name());
|
||||
}
|
||||
}
|
||||
+54
@@ -90,6 +90,10 @@ extern {
|
||||
|
||||
fn getgid() -> gid_t;
|
||||
fn getegid() -> gid_t;
|
||||
|
||||
fn setpwent();
|
||||
fn getpwent() -> *const c_passwd;
|
||||
fn endpwent();
|
||||
}
|
||||
|
||||
|
||||
@@ -385,6 +389,56 @@ pub fn get_effective_groupname() -> Option<String> {
|
||||
}
|
||||
|
||||
|
||||
/// An iterator over every user present on the system.
|
||||
///
|
||||
/// This struct actually requires no fields, but has one hidden one to make it
|
||||
/// `unsafe` to create.
|
||||
pub struct AllUsers(());
|
||||
|
||||
impl AllUsers {
|
||||
|
||||
/// Creates a new iterator over every user present on the system.
|
||||
///
|
||||
/// ## Unsafety
|
||||
///
|
||||
/// This constructor is marked as `unsafe`, which is odd for a crate
|
||||
/// that's meant to be a safe interface. It *has* to be unsafe because
|
||||
/// we cannot guarantee that the underlying C functions,
|
||||
/// `getpwent`/`setpwent`/`endpwent` that iterate over the system's
|
||||
/// `passwd` entries, are called in a thread-safe manner.
|
||||
///
|
||||
/// These functions [modify a global
|
||||
/// state](http://man7.org/linux/man-pages/man3/getpwent.3.html#
|
||||
/// ATTRIBUTES), and if any are used at the same time, the state could
|
||||
/// be reset, resulting in a data race. We cannot even place it behind
|
||||
/// an internal `Mutex`, as there is nothing stopping another `extern`
|
||||
/// function definition from calling it!
|
||||
///
|
||||
/// So to iterate all users, construct the iterator inside an `unsafe`
|
||||
/// block, then make sure to not make a new instance of it until
|
||||
/// iteration is over.
|
||||
pub unsafe fn new() -> AllUsers {
|
||||
setpwent();
|
||||
AllUsers(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AllUsers {
|
||||
fn drop(&mut self) {
|
||||
unsafe { endpwent() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for AllUsers {
|
||||
type Item = User;
|
||||
|
||||
fn next(&mut self) -> Option<User> {
|
||||
unsafe { passwd_to_user(getpwent()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// OS-specific extensions to users and groups.
|
||||
///
|
||||
/// Every OS has a different idea of what data a user or a group comes with.
|
||||
|
||||
+19
-2
@@ -68,7 +68,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use base::{User, Group};
|
||||
use base::{User, Group, AllUsers};
|
||||
use traits::{Users, Groups};
|
||||
|
||||
|
||||
@@ -120,10 +120,27 @@ impl Default for UsersCache {
|
||||
|
||||
impl UsersCache {
|
||||
|
||||
/// Create a new empty cache.
|
||||
/// Creates a new empty cache.
|
||||
pub fn new() -> UsersCache {
|
||||
UsersCache::default()
|
||||
}
|
||||
|
||||
/// Creates a new cache that contains all the users present on the system.
|
||||
///
|
||||
/// This is `unsafe` because we cannot prevent data races if two caches
|
||||
/// were attempted to be initialised on different threads at the same time.
|
||||
pub unsafe fn with_all_users() -> UsersCache {
|
||||
let cache = UsersCache::new();
|
||||
|
||||
for user in AllUsers::new() {
|
||||
let uid = user.uid();
|
||||
let user_arc = Arc::new(user);
|
||||
cache.users.forward.borrow_mut().insert(uid, Some(user_arc.clone()));
|
||||
cache.users.backward.borrow_mut().insert(user_arc.name_arc.clone(), Some(uid));
|
||||
}
|
||||
|
||||
cache
|
||||
}
|
||||
}
|
||||
|
||||
impl Users for UsersCache {
|
||||
|
||||
@@ -120,6 +120,7 @@ pub use base::{get_current_uid, get_current_username};
|
||||
pub use base::{get_effective_uid, get_effective_username};
|
||||
pub use base::{get_current_gid, get_current_groupname};
|
||||
pub use base::{get_effective_gid, get_effective_groupname};
|
||||
pub use base::AllUsers;
|
||||
|
||||
|
||||
pub mod cache;
|
||||
|
||||
Reference in New Issue
Block a user