1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/// The wakeup type defined in the SMBIOS specification.
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum WakeupType {
    Reserved,
    Other,
    Unknown,
    APM_Timer,
    Modem_Ring,
    LAN_Remote,
    Power_Switch,
    PCI_PME,
    AC_Power_Restored,
    Undefined(u8),
}

impl From<u8> for WakeupType {
    fn from(_type: u8) -> WakeupType {
        match _type {
            0 => WakeupType::Reserved,
            1 => WakeupType::Other,
            2 => WakeupType::Unknown,
            3 => WakeupType::APM_Timer,
            4 => WakeupType::Modem_Ring,
            5 => WakeupType::LAN_Remote,
            6 => WakeupType::Power_Switch,
            7 => WakeupType::PCI_PME,
            8 => WakeupType::AC_Power_Restored,
            t => WakeupType::Undefined(t),
        }
    }
}

/// The `System` table defined in the SMBIOS specification.
///
/// Optional fields will only be set if the version of the parsed SMBIOS table
/// is high enough to have defined the field.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct System<'buffer> {
    pub handle: u16,
    pub manufacturer: &'buffer str,
    pub product: &'buffer str,
    pub version: &'buffer str,
    pub serial: &'buffer str,
    pub uuid: Option<[u8; 16]>,
    pub wakeup: Option<WakeupType>,
    pub sku: Option<&'buffer str>,
    pub family: Option<&'buffer str>,
}

impl<'buffer> System<'buffer> {
    pub(crate) fn try_from(structure: super::RawStructure<'buffer>) -> Result<System<'buffer>, super::MalformedStructureError> {
        #[repr(C)]
        #[repr(packed)]
        struct SystemPacked_2_0 {
            manufacturer: u8,
            product: u8,
            version: u8,
            serial: u8,
        }

        #[repr(C)]
        #[repr(packed)]
        struct SystemPacked_2_1 {
            v2_0: SystemPacked_2_0,
            uuid: [u8; 16],
            wakeup: u8,
        }

        #[repr(C)]
        #[repr(packed)]
        struct SystemPacked_2_4 {
            v2_1: SystemPacked_2_1,
            sku: u8,
            family: u8,
        }

        if structure.version < (2, 1).into() {
            let_as_struct!(packed, SystemPacked_2_0, structure.data);

            Ok(System {
                handle: structure.handle,
                manufacturer: structure.find_string(packed.manufacturer)?,
                product: structure.find_string(packed.product)?,
                version: structure.find_string(packed.version)?,
                serial: structure.find_string(packed.serial)?,
                uuid: None,
                wakeup: None,
                sku: None,
                family: None,
            })

        } else if structure.version < (2, 4).into() {
            let_as_struct!(packed, SystemPacked_2_1, structure.data);

            Ok(System {
                handle: structure.handle,
                manufacturer: structure.find_string(packed.v2_0.manufacturer)?,
                product: structure.find_string(packed.v2_0.product)?,
                version: structure.find_string(packed.v2_0.version)?,
                serial: structure.find_string(packed.v2_0.serial)?,
                uuid: Some(packed.uuid),
                wakeup: Some(packed.wakeup.into()),
                sku: None,
                family: None,
            })

        } else {
            let_as_struct!(packed, SystemPacked_2_4, structure.data);

            Ok(System {
                handle: structure.handle,
                manufacturer: structure.find_string(packed.v2_1.v2_0.manufacturer)?,
                product: structure.find_string(packed.v2_1.v2_0.product)?,
                version: structure.find_string(packed.v2_1.v2_0.version)?,
                serial: structure.find_string(packed.v2_1.v2_0.serial)?,
                uuid: Some(packed.v2_1.uuid),
                wakeup: Some(packed.v2_1.wakeup.into()),
                sku: Some(structure.find_string(packed.sku)?),
                family: Some(structure.find_string(packed.family)?),
            })
        }
    }
}