top: implement user count

This commit is contained in:
Bluemangoo
2025-01-23 18:58:13 +08:00
parent 66bbf74cb6
commit ff78299c38
3 changed files with 142 additions and 5 deletions
Generated
+25
View File
@@ -92,6 +92,12 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "build-env"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1522ac6ee801a11bf9ef3f80403f4ede6eb41291fac3dde3de09989679305f25"
[[package]]
name = "bumpalo"
version = "3.16.0"
@@ -420,6 +426,17 @@ dependencies = [
"libc",
]
[[package]]
name = "libsystemd-sys"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed080163caa59cc29b34bce2209b737149a4bac148cd9a8b04e4c12822798119"
dependencies = [
"build-env",
"libc",
"pkg-config",
]
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
@@ -564,6 +581,12 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pkg-config"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -1170,11 +1193,13 @@ dependencies = [
"chrono",
"clap",
"libc",
"libsystemd-sys",
"nix",
"prettytable-rs",
"sysinfo",
"systemstat",
"uucore",
"windows 0.59.0",
]
[[package]]
+6
View File
@@ -22,6 +22,12 @@ chrono = { workspace = true }
systemstat = { workspace = true }
bytesize = { workspace = true }
[target.'cfg(target_os="linux")'.dependencies]
libsystemd-sys = "0.9.3"
[target.'cfg(target_os="windows")'.dependencies]
windows = { version = "0.59.0", features = ["Win32_System_RemoteDesktop"] }
[lib]
path = "src/top.rs"
+111 -5
View File
@@ -51,6 +51,7 @@ pub(crate) fn header(arg: &ArgMatches) -> String {
)
}
#[cfg(not(target_os = "linux"))]
fn todo() -> String {
"TODO".into()
}
@@ -85,9 +86,116 @@ fn uptime() -> String {
res
}
//TODO: Implement active user count
#[inline]
fn format_user(user: u64) -> String {
match user {
0 => "0 user".to_string(),
1 => "1 user".to_string(),
_ => format!("{} users", user),
}
}
#[cfg(target_os = "windows")]
fn user() -> String {
todo()
use windows::{core::*, Win32::System::RemoteDesktop::*};
let mut num_user = 0;
unsafe {
let mut session_info_ptr = std::ptr::null_mut();
let mut session_count = 0;
WTSEnumerateSessionsW(
Some(WTS_CURRENT_SERVER_HANDLE),
0,
1,
&mut session_info_ptr,
&mut session_count,
)
.unwrap();
let sessions = std::slice::from_raw_parts(session_info_ptr, session_count as usize);
for session in sessions {
let mut buffer = PWSTR::null();
let mut bytes_returned = 0;
WTSQuerySessionInformationW(
Some(WTS_CURRENT_SERVER_HANDLE),
session.SessionId,
WTS_INFO_CLASS(5),
&mut buffer,
&mut bytes_returned,
)
.unwrap();
let username = PWSTR(buffer.0).to_string().unwrap_or_default();
if !username.is_empty() {
num_user += 1;
}
WTSFreeMemory(buffer.0 as _);
}
WTSFreeMemory(session_info_ptr as _);
}
format_user(num_user)
}
#[cfg(unix)]
// see: https://gitlab.com/procps-ng/procps/-/blob/4740a0efa79cade867cfc7b32955fe0f75bf5173/library/uptime.c#L63-L115
fn user() -> String {
use uucore::utmpx::Utmpx;
#[cfg(target_os = "linux")]
unsafe {
use libc::free;
use libsystemd_sys::daemon::sd_booted;
use libsystemd_sys::login::{sd_get_sessions, sd_session_get_class};
use std::ffi::{c_char, c_void, CStr};
use std::ptr;
// systemd
if sd_booted() > 0 {
let mut sessions_list: *mut *mut c_char = ptr::null_mut();
let mut num_user = 0;
let sessions = sd_get_sessions(&mut sessions_list); // rust-systemd does not implement this
if sessions > 0 {
for i in 0..sessions {
let mut class: *mut c_char = ptr::null_mut();
if sd_session_get_class(
*sessions_list.add(i as usize) as *const c_char,
&mut class,
) < 0
{
continue;
}
if CStr::from_ptr(class).to_str().unwrap().starts_with("user") {
num_user += 1;
}
free(class as *mut c_void);
}
}
for i in 0..sessions {
free(*sessions_list.add(i as usize) as *mut c_void);
}
free(sessions_list as *mut c_void);
return format_user(num_user);
}
}
// utmpx
let mut num_user = 0;
Utmpx::iter_all_records().for_each(|ut| {
if ut.record_type() == 7 && !ut.user().is_empty() {
num_user += 1;
}
});
format_user(num_user)
}
#[cfg(not(target_os = "windows"))]
@@ -214,9 +322,7 @@ fn memory(arg: &ArgMatches) -> String {
"e" => (1_152_921_504_606_846_976, "EiB"),
_ => (bytesize::MIB, "MiB"),
},
None => {
(bytesize::MIB, "MiB")
}
None => (bytesize::MIB, "MiB"),
};
format!(