pub(crate) const K_IO_PLATFORM_SERIAL_NUMBER_KEY: &str = "IOPlatformSerialNumber";
pub(crate) const K_DA_DISK_DESCRIPTION_MEDIA_UUID_KEY: &str = "DAMediaUUID";
#[allow(dead_code)]
#[derive(Debug)]
pub(crate) struct StatFS {
pub f_bsize: u32,
pub f_iosize: i32,
pub f_blocks: u64,
pub f_bfree: u64,
pub f_bavail: u64,
pub f_files: u64,
pub f_ffree: u64,
pub f_fsid: [u32; 2],
pub f_owner: u32,
pub f_type: u32,
pub f_flags: u32,
pub f_fssubtype: u32,
pub f_fstypename: String,
pub f_mntonname: String,
pub f_mntfromname: String,
pub f_reserved: [u32; 8],
}
pub(crate) fn platform_serial_number() -> Option<String> {
let output = run_command("ioreg", &["-rd1", "-c", "IOPlatformExpertDevice"])?;
parse_quoted_property(&output, K_IO_PLATFORM_SERIAL_NUMBER_KEY)
}
pub(crate) fn media_uuid(mount_point: &str) -> Option<String> {
let output = run_command("diskutil", &["info", mount_point])?;
parse_property_line(&output, "Volume UUID:")
}
fn run_command(program: &str, arguments: &[&str]) -> Option<String> {
let output = std::process::Command::new(program)
.args(arguments)
.output()
.ok()?;
if !output.status.success() {
return None;
}
String::from_utf8(output.stdout).ok()
}
fn parse_quoted_property(output: &str, key: &str) -> Option<String> {
for line in output.lines() {
let Some(rest) = line.trim().strip_prefix('"') else {
continue;
};
let Some((name, rest)) = rest.split_once('"') else {
continue;
};
if name != key {
continue;
}
let Some(rest) = rest.trim().strip_prefix('=') else {
continue;
};
let rest = rest.trim();
let Some(rest) = rest.strip_prefix('"') else {
continue;
};
let Some(value) = rest.strip_suffix('"') else {
continue;
};
return Some(value.to_string());
}
None
}
fn parse_property_line(output: &str, key: &str) -> Option<String> {
for line in output.lines() {
let Some((name, value)) = line.split_once(':') else {
continue;
};
if name.trim() != key.trim() {
continue;
}
let value = value.trim();
if value.is_empty() || value == "(null)" {
return None;
}
return Some(value.to_string());
}
None
}