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
166 use windows_registry::LOCAL_MACHINE;
167 use windows_sys::Win32::Foundation::GetLastError;
168 use windows_sys::Win32::System::Registry::{KEY_READ, KEY_WOW64_64KEY};
169 use windows_sys::Win32::System::Threading::{GetCurrentProcess, IsWow64Process};
170
171 fn machine_uid_is_wow64() -> Result<bool, Box<dyn Error>> {
172 unsafe {
173 let mut is_wow64: i32 = 0;
174 if IsWow64Process(GetCurrentProcess(), &mut is_wow64) == 0 {
175 return Err(From::from(format!("Failed to determine whether the specified process is running under WOW64 or an Intel64 of x64 processor: {}", GetLastError())));
176 }
177
178 Ok(is_wow64 == 1)
179 }
180 }
181
182 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
184 let flag = if machine_uid_is_wow64()? && cfg!(target_pointer_width = "32") {
185 KEY_READ | KEY_WOW64_64KEY
186 } else {
187 KEY_READ
188 };
189
190 let key = LOCAL_MACHINE
191 .options()
192 .access(flag)
193 .open("SOFTWARE\\Microsoft\\Cryptography")?;
194 let id = key.get_string("MachineGuid")?;
195
196 Ok(id.trim().to_string())
197 }
198}
199
200#[cfg(target_os = "illumos")]
201pub mod machine_id {
202 use std::error::Error;
203
204 pub fn get_machine_id() -> Result<String, Box<dyn Error>> {
206 Ok(format!("{:x}", unsafe { libc::gethostid() }))
207 }
208}
209
210pub use machine_id::get_machine_id as get;