use std::path::Path;
pub fn find_ci(haystack: &str, needle: &str) -> bool {
haystack.to_lowercase().contains(&needle.to_lowercase())
}
pub fn find(haystack: &str, needle: &str) -> bool {
haystack.contains(needle)
}
pub fn read_file(path: &str) -> Option<String> {
std::fs::read_to_string(path).ok()
}
pub fn file_exists(path: &str) -> bool {
Path::new(path).exists()
}
pub fn dir_exists(path: &str) -> bool {
Path::new(path).is_dir()
}
pub fn run_command(cmd: &str, args: &[&str]) -> Option<String> {
std::process::Command::new(cmd)
.args(args)
.output()
.ok()
.and_then(|output| {
if output.status.success() {
String::from_utf8(output.stdout).ok()
} else {
None
}
})
}
pub fn get_hostname() -> Option<String> {
#[cfg(unix)]
{
run_command("hostname", &[])
.map(|s| s.trim().to_string())
}
#[cfg(windows)]
{
std::env::var("COMPUTERNAME").ok()
}
}
pub fn get_username() -> Option<String> {
#[cfg(unix)]
{
std::env::var("USER")
.or_else(|_| std::env::var("LOGNAME"))
.ok()
}
#[cfg(windows)]
{
std::env::var("USERNAME").ok()
}
}
pub fn thread_count() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1)
}
#[cfg(target_os = "windows")]
pub mod win {
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
pub fn to_wide(s: &str) -> Vec<u16> {
OsStr::new(s).encode_wide().chain(std::iter::once(0)).collect()
}
pub fn read_registry_string(hive: &str, subkey: &str, value_name: &str) -> Option<String> {
use winreg::enums::*;
use winreg::RegKey;
let hkey = match hive {
"HKLM" | "HKEY_LOCAL_MACHINE" => RegKey::predef(HKEY_LOCAL_MACHINE),
"HKCU" | "HKEY_CURRENT_USER" => RegKey::predef(HKEY_CURRENT_USER),
"HKCR" | "HKEY_CLASSES_ROOT" => RegKey::predef(HKEY_CLASSES_ROOT),
_ => return None,
};
let key = hkey.open_subkey(subkey).ok()?;
let val: String = key.get_value(value_name).ok()?;
Some(val)
}
pub fn enum_registry_subkeys(hive: &str, subkey: &str) -> Vec<String> {
use winreg::enums::*;
use winreg::RegKey;
let hkey = match hive {
"HKLM" | "HKEY_LOCAL_MACHINE" => RegKey::predef(HKEY_LOCAL_MACHINE),
"HKCU" | "HKEY_CURRENT_USER" => RegKey::predef(HKEY_CURRENT_USER),
_ => return Vec::new(),
};
match hkey.open_subkey(subkey) {
Ok(key) => key.enum_keys().filter_map(|k| k.ok()).collect(),
Err(_) => Vec::new(),
}
}
pub fn is_dll_loaded(dll_name: &str) -> bool {
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::core::PCWSTR;
let wide = to_wide(dll_name);
unsafe {
GetModuleHandleW(PCWSTR(wide.as_ptr())).is_ok()
}
}
pub fn mutex_exists(name: &str) -> bool {
use windows::Win32::System::Threading::OpenMutexW;
use windows::Win32::System::Threading::SYNCHRONIZATION_ACCESS_RIGHTS;
use windows::core::PCWSTR;
let wide = to_wide(name);
unsafe {
let result = OpenMutexW(
SYNCHRONIZATION_ACCESS_RIGHTS(0x00100000), false,
PCWSTR(wide.as_ptr()),
);
result.is_ok()
}
}
}
#[cfg(target_os = "linux")]
pub mod linux {
use std::fs;
use std::path::Path;
pub fn read_sys_file(path: &str) -> Option<String> {
fs::read_to_string(path).ok().map(|s| s.trim().to_string())
}
pub fn is_module_loaded(module_name: &str) -> bool {
if let Some(content) = super::read_file("/proc/modules") {
content.lines().any(|line| {
line.split_whitespace()
.next()
.map_or(false, |name| name == module_name)
})
} else {
false
}
}
pub fn list_processes() -> Vec<String> {
let mut procs = Vec::new();
if let Ok(entries) = fs::read_dir("/proc") {
for entry in entries.flatten() {
let name = entry.file_name();
let name_str = name.to_string_lossy();
if name_str.chars().all(|c| c.is_ascii_digit()) {
let comm_path = format!("/proc/{}/comm", name_str);
if let Ok(comm) = fs::read_to_string(&comm_path) {
procs.push(comm.trim().to_string());
}
}
}
}
procs
}
pub fn read_dmi_field(field: &str) -> Option<String> {
let path = format!("/sys/devices/virtual/dmi/id/{}", field);
if Path::new(&path).exists() {
fs::read_to_string(&path).ok().map(|s| s.trim().to_string())
} else {
None
}
}
pub fn get_mac_address() -> Option<String> {
let net_dir = "/sys/class/net";
if let Ok(entries) = fs::read_dir(net_dir) {
for entry in entries.flatten() {
let iface = entry.file_name().to_string_lossy().to_string();
if iface == "lo" {
continue;
}
let addr_path = format!("{}/{}/address", net_dir, iface);
if let Ok(addr) = fs::read_to_string(&addr_path) {
let addr = addr.trim().to_string();
if !addr.is_empty() && addr != "00:00:00:00:00:00" {
return Some(addr);
}
}
}
}
None
}
}
#[cfg(target_os = "macos")]
pub mod macos {
pub fn sysctl_string(key: &str) -> Option<String> {
super::run_command("sysctl", &["-n", key])
.map(|s| s.trim().to_string())
}
pub fn system_profiler(data_type: &str) -> Option<String> {
super::run_command("system_profiler", &[data_type])
}
pub fn ioreg(args: &[&str]) -> Option<String> {
super::run_command("ioreg", args)
}
}