@@ -51,6 +51,7 @@ pub(crate) fn header(arg: &ArgMatches) -> String {
51
51
)
52
52
}
53
53
54
+ #[ cfg( not( target_os = "linux" ) ) ]
54
55
fn todo ( ) -> String {
55
56
"TODO" . into ( )
56
57
}
@@ -85,11 +86,77 @@ fn uptime() -> String {
85
86
res
86
87
}
87
88
89
+ fn format_user ( user : u64 ) -> String {
90
+ match user {
91
+ 0 => "0 user" . to_string ( ) ,
92
+ 1 => "1 user" . to_string ( ) ,
93
+ _ => format ! ( "{} users" , user) ,
94
+ }
95
+ }
96
+
88
97
//TODO: Implement active user count
98
+ #[ cfg( not( target_os = "linux" ) ) ]
89
99
fn user ( ) -> String {
90
100
todo ( )
91
101
}
92
102
103
+ #[ cfg( target_os = "linux" ) ]
104
+ // see: https://gitlab.com/procps-ng/procps/-/blob/4740a0efa79cade867cfc7b32955fe0f75bf5173/library/uptime.c#L63-L115
105
+ fn user ( ) -> String {
106
+ use libc:: { endutxent, free, getutxent, setutxent} ;
107
+ use libsystemd_sys:: daemon:: sd_booted;
108
+ use libsystemd_sys:: login:: { sd_get_sessions, sd_session_get_class} ;
109
+ use std:: ffi:: { c_char, c_void, CStr } ;
110
+ use std:: ptr;
111
+
112
+ unsafe {
113
+ // systemd
114
+ if sd_booted ( ) > 0 {
115
+ let mut sessions_list: * mut * mut c_char = ptr:: null_mut ( ) ;
116
+ let mut num_user = 0 ;
117
+ let sessions = sd_get_sessions ( & mut sessions_list) ; // rust-systemd does not implement this
118
+
119
+ if sessions > 0 {
120
+ for i in 0 ..sessions {
121
+ let mut class: * mut c_char = ptr:: null_mut ( ) ;
122
+
123
+ if sd_session_get_class (
124
+ * sessions_list. add ( i as usize ) as * const c_char ,
125
+ & mut class,
126
+ ) < 0
127
+ {
128
+ continue ;
129
+ }
130
+ if CStr :: from_ptr ( class) . to_str ( ) . unwrap ( ) . starts_with ( "user" ) {
131
+ num_user += 1 ;
132
+ }
133
+ free ( class as * mut c_void ) ;
134
+ }
135
+ }
136
+
137
+ for i in 0 ..sessions {
138
+ free ( * sessions_list. add ( i as usize ) as * mut c_void ) ;
139
+ }
140
+ free ( sessions_list as * mut c_void ) ;
141
+
142
+ return format_user ( num_user) ;
143
+ }
144
+
145
+ // utmp
146
+ let mut num_user = 0 ;
147
+ setutxent ( ) ;
148
+ let mut ut = getutxent ( ) ;
149
+ while !ut. is_null ( ) {
150
+ if ( ( * ut) . ut_type == 7 ) && ( ( * ut) . ut_user [ 0 ] != ( '\0' as i8 ) ) {
151
+ num_user += 1 ;
152
+ }
153
+ ut = getutxent ( ) ;
154
+ }
155
+ endutxent ( ) ;
156
+ format_user ( num_user)
157
+ }
158
+ }
159
+
93
160
#[ cfg( not( target_os = "windows" ) ) ]
94
161
fn load_average ( ) -> String {
95
162
let binding = systemstat ( ) . read ( ) . unwrap ( ) ;
@@ -214,9 +281,7 @@ fn memory(arg: &ArgMatches) -> String {
214
281
"e" => ( 1_152_921_504_606_846_976 , "EiB" ) ,
215
282
_ => ( bytesize:: MIB , "MiB" ) ,
216
283
} ,
217
- None => {
218
- ( bytesize:: MIB , "MiB" )
219
- }
284
+ None => ( bytesize:: MIB , "MiB" ) ,
220
285
} ;
221
286
222
287
format ! (
0 commit comments