disk-serial-number 0.2.1

A Rust library to get disk serial numbers across different platforms.
Documentation
#![cfg(target_os = "linux")]

use crate::{DiskInfo, DiskInfoProvider, ProviderError};
use serde::Deserialize;
use std::process::Command;

#[derive(Deserialize)]
struct LsblkDevice {
    name: String,
    model: Option<String>,
    serial: Option<String>,
    // We only select devices of type "disk"
    #[serde(rename = "type")]
    device_type: String,
    #[serde(rename = "rm")]
    removable: bool,
    hotplug: bool,
}

#[derive(Deserialize)]
struct LsblkOutput {
    blockdevices: Vec<LsblkDevice>,
}

pub struct LinuxProvider;

impl DiskInfoProvider for LinuxProvider {
    fn get_all_disks() -> Result<Vec<DiskInfo>, ProviderError> {
        let output = Command::new("lsblk")
            .args(["-o", "NAME,MODEL,SERIAL,TYPE,RM,HOTPLUG", "-J", "-b", "-d"]) // -d: only show disks themselves, not partitions
            .output()?;

        if !output.status.success() {
            return Err(ProviderError::CommandUnsuccessful(
                String::from_utf8_lossy(&output.stderr).into(),
            ));
        }

        let json_str = String::from_utf8_lossy(&output.stdout);
        let parsed: LsblkOutput = serde_json::from_str(&json_str)?;

        let disks = parsed
            .blockdevices
            .into_iter()
            .filter(|dev| dev.device_type == "disk") // Filter devices with type "disk"
            .map(|dev| DiskInfo {
                name: dev.name.trim().to_string(),
                model: dev.model.and_then(|m| {
                    if m.trim().is_empty() {
                        None
                    } else {
                        Some(m.trim().to_string())
                    }
                }),
                serial_number: dev.serial.and_then(|s| {
                    if s.trim().is_empty() {
                        None
                    } else {
                        Some(s.trim().to_string())
                    }
                }),
                removable: Some(dev.removable || dev.hotplug),
            })
            .collect();

        Ok(disks)
    }
}