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