1use std::error::Error;
72use std::fs::File;
73use std::io::prelude::*;
74
75#[allow(dead_code)]
76fn read_file(file_path: &str) -> Result<String, Box<dyn Error>> {
77 let mut fd = File::open(file_path)?;
78 let mut content = String::new();
79 fd.read_to_string(&mut content)?;
80 Ok(content.trim().to_string())
81}
82
83#[cfg(target_os = "linux")]
84pub mod machine_id {
85 use super::read_file;
86 use std::error::Error;
87
88 const DBUS_PATH: &str = "/var/lib/dbus/machine-id";
90 const DBUS_PATH_ETC: &str = "/etc/machine-id";
92
93 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
95 match read_file(DBUS_PATH) {
96 Ok(machine_id) => Ok(machine_id),
97 Err(_) => Ok(read_file(DBUS_PATH_ETC)?),
98 }
99 }
100}
101
102#[cfg(any(
103 target_os = "freebsd",
104 target_os = "dragonfly",
105 target_os = "openbsd",
106 target_os = "netbsd"
107))]
108pub mod machine_id {
109 use super::read_file;
110 use std::error::Error;
111 use std::process::Command;
112
113 const HOST_ID_PATH: &str = "/etc/hostid";
114
115 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
117 match read_file(HOST_ID_PATH) {
118 Ok(machine_id) => Ok(machine_id),
119 Err(_) => Ok(read_from_kenv()?),
120 }
121 }
122
123 fn read_from_kenv() -> Result<String, Box<dyn Error>> {
124 let output = Command::new("kenv")
125 .args(&["-q", "smbios.system.uuid"])
126 .output()?;
127 let content = String::from_utf8_lossy(&output.stdout);
128 Ok(content.trim().to_string())
129 }
130}
131
132#[cfg(target_os = "macos")]
133mod machine_id {
134 use std::error::Error;
136 use std::process::Command;
137
138 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
140 let output = Command::new("ioreg")
141 .args(&["-rd1", "-c", "IOPlatformExpertDevice"])
142 .output()?;
143 let content = String::from_utf8_lossy(&output.stdout);
144 extract_id(&content)
145 }
146
147 fn extract_id(content: &str) -> Result<String, Box<dyn Error>> {
148 let lines = content.split('\n');
149 for line in lines {
150 if line.contains("IOPlatformUUID") {
151 let k: Vec<&str> = line.rsplitn(2, '=').collect();
152 let id = k[0].trim_matches(|c: char| c == '"' || c.is_whitespace());
153 return Ok(id.to_string());
154 }
155 }
156 Err(From::from(
157 "No matching IOPlatformUUID in `ioreg -rd1 -c IOPlatformExpertDevice` command.",
158 ))
159 }
160}
161
162#[cfg(target_os = "windows")]
163pub mod machine_id {
164 use std::error::Error;
165 use std::ffi::c_void;
166 use winreg::enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_64KEY};
167 use winreg::RegKey;
168
169 type BOOL = i32;
170 type HANDLE = *mut c_void;
171 type PBOOL = *mut BOOL;
172
173 extern "system" {
174 fn GetModuleHandleA(lpModuleName: *const u8) -> HANDLE;
175 fn GetProcAddress(hModule: HANDLE, lpProcName: *const u8) -> *const c_void;
176 fn GetCurrentProcess() -> HANDLE;
177 }
178
179 const KERNEL32: *const u8 = b"kernel32.dll\0".as_ptr();
180 const ISWOW64PROCESS: *const u8 = b"IsWow64Process\0".as_ptr();
181
182 type LpfnIswow64process = unsafe extern "system" fn(HANDLE, PBOOL) -> BOOL;
183
184 fn machine_uid_is_wow64() -> bool {
185 unsafe {
186 let mut b_is_wow64: BOOL = 0;
187 let h_module = GetModuleHandleA(KERNEL32);
188 let fn_is_wow64_process: Option<LpfnIswow64process> =
189 std::mem::transmute(GetProcAddress(h_module, ISWOW64PROCESS));
190
191 if let Some(fn_is_wow64_process) = fn_is_wow64_process {
192 if fn_is_wow64_process(GetCurrentProcess(), &mut b_is_wow64) == 0 {
193 }
195 }
196 b_is_wow64 == 1
197 }
198 }
199
200 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
202 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
203
204 let flag = if machine_uid_is_wow64() && cfg!(target_pointer_width = "32") {
205 KEY_READ | KEY_WOW64_64KEY
206 } else {
207 KEY_READ
208 };
209
210 let crypto = hklm.open_subkey_with_flags("SOFTWARE\\Microsoft\\Cryptography", flag)?;
211 let id: String = crypto.get_value("MachineGuid")?;
212
213 Ok(id.trim().to_string())
214 }
215}
216
217#[cfg(target_os = "illumos")]
218pub mod machine_id {
219 use std::error::Error;
220
221 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
223 Ok(format!("{:x}", unsafe { libc::gethostid() }))
224 }
225}
226
227pub use machine_id::get_machine_id as get;