use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
#[allow(dead_code)]
fn read_file(file_path: &str) -> Result<String, Box<dyn Error>> {
let mut fd = File::open(file_path)?;
let mut content = String::new();
fd.read_to_string(&mut content)?;
Ok(content.trim().to_string())
}
#[cfg(target_os = "linux")]
pub mod machine_id {
use super::read_file;
use std::error::Error;
const DBUS_PATH: &str = "/var/lib/dbus/machine-id";
const DBUS_PATH_ETC: &str = "/etc/machine-id";
pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
match read_file(DBUS_PATH) {
Ok(machine_id) => Ok(machine_id),
Err(_) => Ok(read_file(DBUS_PATH_ETC)?),
}
}
}
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd"
))]
pub mod machine_id {
use super::read_file;
use std::error::Error;
use std::process::Command;
const HOST_ID_PATH: &str = "/etc/hostid";
pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
match read_file(HOST_ID_PATH) {
Ok(machine_id) => Ok(machine_id),
Err(_) => Ok(read_from_kenv()?),
}
}
fn read_from_kenv() -> Result<String, Box<dyn Error>> {
let output = Command::new("kenv")
.args(&["-q", "smbios.system.uuid"])
.output()?;
let content = String::from_utf8_lossy(&output.stdout);
Ok(content.trim().to_string())
}
}
#[cfg(target_os = "macos")]
mod machine_id {
use std::error::Error;
use std::process::Command;
pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
let output = Command::new("ioreg")
.args(&["-rd1", "-c", "IOPlatformExpertDevice"])
.output()?;
let content = String::from_utf8_lossy(&output.stdout);
extract_id(&content)
}
fn extract_id(content: &str) -> Result<String, Box<dyn Error>> {
let lines = content.split('\n');
for line in lines {
if line.contains("IOPlatformUUID") {
let k: Vec<&str> = line.rsplitn(2, '=').collect();
let id = k[0].trim_matches(|c: char| c == '"' || c.is_whitespace());
return Ok(id.to_string());
}
}
Err(From::from(
"No matching IOPlatformUUID in `ioreg -rd1 -c IOPlatformExpertDevice` command.",
))
}
}
#[cfg(target_os = "windows")]
pub mod machine_id {
use std::error::Error;
use windows_registry::LOCAL_MACHINE;
use windows_sys::Win32::Foundation::GetLastError;
use windows_sys::Win32::System::Registry::{KEY_READ, KEY_WOW64_64KEY};
use windows_sys::Win32::System::Threading::{GetCurrentProcess, IsWow64Process};
fn machine_uid_is_wow64() -> Result<bool, Box<dyn Error>> {
unsafe {
let mut is_wow64: i32 = 0;
if IsWow64Process(GetCurrentProcess(), &mut is_wow64) == 0 {
return Err(From::from(format!("Failed to determine whether the specified process is running under WOW64 or an Intel64 of x64 processor: {}", GetLastError())));
}
Ok(is_wow64 == 1)
}
}
pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
let flag = if machine_uid_is_wow64()? && cfg!(target_pointer_width = "32") {
KEY_READ | KEY_WOW64_64KEY
} else {
KEY_READ
};
let key = LOCAL_MACHINE
.options()
.access(flag)
.open("SOFTWARE\\Microsoft\\Cryptography")?;
let id = key.get_string("MachineGuid")?;
Ok(id.trim().to_string())
}
}
#[cfg(target_os = "illumos")]
pub mod machine_id {
use std::error::Error;
pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
Ok(format!("{:x}", unsafe { libc::gethostid() }))
}
}
pub use machine_id::get_machine_id as get;