@@ -20,6 +20,11 @@ pub use self::pivot_root::*;
20
20
#[ cfg( any( target_os = "android" , target_os = "freebsd" ,
21
21
target_os = "linux" , target_os = "openbsd" ) ) ]
22
22
pub use self :: setres:: * ;
23
+ #[ cfg( not( any( target_os = "android" ,
24
+ target_os = "ios" ,
25
+ target_os = "macos" ,
26
+ target_env = "musl" ) ) ) ]
27
+ pub use self :: usergroupiter:: * ;
23
28
24
29
/// User identifier
25
30
///
@@ -2425,6 +2430,13 @@ pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
2425
2430
Errno :: result ( res) . map ( drop)
2426
2431
}
2427
2432
2433
+ #[ cfg( not( any( target_os = "android" ,
2434
+ target_os = "ios" ,
2435
+ target_os = "macos" ,
2436
+ target_env = "musl" ) ) ) ]
2437
+ /// Default buffer size for system user and group querying functions
2438
+ const PWGRP_BUFSIZE : usize = 1024 ;
2439
+
2428
2440
/// Representation of a User, based on `libc::passwd`
2429
2441
///
2430
2442
/// The reason some fields in this struct are `String` and others are `CString` is because some
@@ -2676,3 +2688,164 @@ impl Group {
2676
2688
} )
2677
2689
}
2678
2690
}
2691
+
2692
+ #[ cfg( not( any( target_os = "android" ,
2693
+ target_os = "ios" ,
2694
+ target_os = "macos" ,
2695
+ target_env = "musl" ) ) ) ]
2696
+ mod usergroupiter {
2697
+ use libc:: { self , c_char} ;
2698
+ use Result ;
2699
+ use errno:: Errno ;
2700
+ use super :: { Error , User , Group , PWGRP_BUFSIZE } ;
2701
+ use std:: { mem, ptr} ;
2702
+
2703
+ /// Used to get all of the users on the system.
2704
+ ///
2705
+ /// # Examples
2706
+ ///
2707
+ /// ```
2708
+ /// # use nix::unistd::Users;
2709
+ /// Users::default()
2710
+ /// .map(|e| e.map(|pw| println!("{}\t{}", pw.name, pw.uid)))
2711
+ /// .collect::<Vec<_>>();
2712
+ ///
2713
+ /// ```
2714
+ ///
2715
+ /// # Safety
2716
+ ///
2717
+ /// This iterator should not be used in different threads without synchronization; while doing so
2718
+ /// will not cause undefined behavior, because modern systems lack re-entrant versions of
2719
+ /// `setpwent` and `endpwent`, it is very likely that iterators running in different threads will
2720
+ /// yield different numbers of items.
2721
+ #[ derive( Debug , Clone , Eq , PartialEq , Hash ) ]
2722
+ pub struct Users ( usize ) ;
2723
+
2724
+ impl Default for Users {
2725
+ fn default ( ) -> Self {
2726
+ Users :: with_capacity ( PWGRP_BUFSIZE )
2727
+ }
2728
+ }
2729
+
2730
+ impl Users {
2731
+ /// Create a new `Users` instance with given capacity.
2732
+ pub fn with_capacity ( bufsize : usize ) -> Self {
2733
+ unsafe { libc:: setpwent ( ) ; }
2734
+ Users ( bufsize)
2735
+ }
2736
+
2737
+ /// Get the buffer size this `Users` instance was created with.
2738
+ pub fn bufsize ( & self ) -> usize {
2739
+ self . 0
2740
+ }
2741
+ }
2742
+
2743
+ impl Iterator for Users {
2744
+ type Item = Result < User > ;
2745
+ fn next ( & mut self ) -> Option < Result < User > > {
2746
+ let mut cbuf = vec ! [ 0 as c_char; self . 0 ] ;
2747
+ let mut pwd = mem:: MaybeUninit :: < libc:: passwd > :: uninit ( ) ;
2748
+ let mut res = ptr:: null_mut ( ) ;
2749
+
2750
+ let error = unsafe {
2751
+ Errno :: clear ( ) ;
2752
+ libc:: getpwent_r (
2753
+ pwd. as_mut_ptr ( ) ,
2754
+ cbuf. as_mut_ptr ( ) ,
2755
+ self . 0 ,
2756
+ & mut res
2757
+ )
2758
+ } ;
2759
+
2760
+ let pwd = unsafe { pwd. assume_init ( ) } ;
2761
+
2762
+ if error == 0 && !res. is_null ( ) {
2763
+ Some ( Ok ( User :: from ( & pwd) ) )
2764
+ } else if error == libc:: ERANGE {
2765
+ Some ( Err ( Error :: Sys ( Errno :: last ( ) ) ) )
2766
+ } else {
2767
+ None
2768
+ }
2769
+ }
2770
+ }
2771
+
2772
+ impl Drop for Users {
2773
+ fn drop ( & mut self ) {
2774
+ unsafe { libc:: endpwent ( ) } ;
2775
+ }
2776
+ }
2777
+
2778
+ /// Used to get all of the groups on the system.
2779
+ ///
2780
+ /// # Examples
2781
+ ///
2782
+ /// ```
2783
+ /// # use nix::unistd::Groups;
2784
+ /// Groups::default()
2785
+ /// .map(|e| e.map(|gr| println!("{}\t{}", gr.name, gr.gid)))
2786
+ /// .collect::<Vec<_>>();
2787
+ /// ```
2788
+ ///
2789
+ /// # Safety
2790
+ ///
2791
+ /// This iterator should not be used in different threads without synchronization; while doing so
2792
+ /// will not cause undefined behavior, because modern systems lack re-entrant versions of
2793
+ /// `setgrent` and `endgrent`, it is very likely that iterators running in different threads will
2794
+ /// yield different numbers of items.
2795
+ #[ derive( Debug , Clone , Eq , PartialEq , Hash ) ]
2796
+ pub struct Groups ( usize ) ;
2797
+
2798
+ impl Default for Groups {
2799
+ fn default ( ) -> Self {
2800
+ Groups :: with_capacity ( PWGRP_BUFSIZE )
2801
+ }
2802
+ }
2803
+
2804
+ impl Groups {
2805
+ /// Create a new `Groups` instance with given capacity.
2806
+ pub fn with_capacity ( bufsize : usize ) -> Self {
2807
+ unsafe { libc:: setgrent ( ) ; }
2808
+ Groups ( bufsize)
2809
+ }
2810
+
2811
+ /// Get the buffer size this `Users` instance was created with.
2812
+ pub fn bufsize ( & self ) -> usize {
2813
+ self . 0
2814
+ }
2815
+ }
2816
+
2817
+ impl Iterator for Groups {
2818
+ type Item = Result < Group > ;
2819
+ fn next ( & mut self ) -> Option < Result < Group > > {
2820
+ let mut cbuf = vec ! [ 0 as c_char; self . 0 ] ;
2821
+ let mut grp = mem:: MaybeUninit :: < libc:: group > :: uninit ( ) ;
2822
+ let mut res = ptr:: null_mut ( ) ;
2823
+
2824
+ let error = unsafe {
2825
+ Errno :: clear ( ) ;
2826
+ libc:: getgrent_r (
2827
+ grp. as_mut_ptr ( ) ,
2828
+ cbuf. as_mut_ptr ( ) ,
2829
+ self . 0 ,
2830
+ & mut res
2831
+ )
2832
+ } ;
2833
+
2834
+ let grp = unsafe { grp. assume_init ( ) } ;
2835
+
2836
+ if error == 0 && !res. is_null ( ) {
2837
+ Some ( Ok ( Group :: from ( & grp) ) )
2838
+ } else if error == libc:: ERANGE {
2839
+ Some ( Err ( Error :: Sys ( Errno :: last ( ) ) ) )
2840
+ } else {
2841
+ None
2842
+ }
2843
+ }
2844
+ }
2845
+
2846
+ impl Drop for Groups {
2847
+ fn drop ( & mut self ) {
2848
+ unsafe { libc:: endgrent ( ) } ;
2849
+ }
2850
+ }
2851
+ }
0 commit comments