sysfs_serde/
sysfs_serde.rs1use crate::pci_attributes::PciAttributes;
2use crate::uevent::UEvent;
3use crate::usb_attributes::UsbAttributes;
4#[cfg(feature = "serde")]
5use serde::Serialize;
6use std::collections::HashMap;
7use std::fmt;
8use std::fs::*;
9use std::os::unix::fs::MetadataExt;
10use std::path::Path;
11use std::str::FromStr;
12
13#[cfg_attr(feature = "serde", derive(Serialize))]
16#[derive(Default)]
17pub struct GenericClassAttributes {
18 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
19 pub uevent: Option<UEvent>,
20 #[cfg_attr(
21 feature = "serde",
22 serde(flatten, skip_serializing_if = "HashMap::is_empty")
23 )]
24 pub attributes: HashMap<String, String>,
25}
26
27type SysPath = String;
28pub type UsbDevices = HashMap<SysPath, UsbAttributes>;
29pub type PciDevices = HashMap<SysPath, PciAttributes>;
30pub type DmiInfo = HashMap<SysPath, GenericClassAttributes>;
31pub type ThermalInfo = HashMap<SysPath, GenericClassAttributes>;
32
33pub enum SysFsType {
35 BusUSB(UsbDevices),
36 BusPCI(PciDevices),
37 ClassDMI(DmiInfo),
38 ClassThermal(ThermalInfo),
39}
40
41impl fmt::Display for SysFsType {
42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43 use crate::SysFsType::*;
44 write!(
45 f,
46 "{}",
47 match self {
48 BusUSB(_) => "USB",
49 BusPCI(_) => "PCI",
50 ClassDMI(_) => "DMI",
51 ClassThermal(_) => "Thermal",
52 }
53 )
54 }
55}
56
57impl From<&mut SysFsType> for &Path {
58 fn from(kind: &mut SysFsType) -> Self {
59 use crate::SysFsType::*;
60 match kind {
61 BusUSB(_) => Path::new("/sys/bus/usb/devices/"),
62 BusPCI(_) => Path::new("/sys/bus/pci/devices/"),
63 ClassDMI(_) => Path::new("/sys/class/dmi/"),
64 ClassThermal(_) => Path::new("/sys/class/thermal"),
65 }
66 }
67}
68
69#[cfg_attr(feature = "serde", derive(Serialize))]
72#[derive(Default)]
73pub struct SysFs {}
74impl SysFs {
75 fn read_generic<F, P>(path: P, mut f: F) -> Result<(), std::io::Error>
77 where
78 F: FnMut(&str, Result<Vec<u8>, std::io::Error>),
79 P: AsRef<Path>,
80 {
81 for entry in read_dir(path)? {
82 if let Ok(entry) = entry {
83 if metadata(entry.path())?.mode() & 0o400 != 0 && entry.path().is_file() {
84 if let Some(key) = entry.path().file_name() {
85 let key = &key.to_string_lossy();
86 match std::fs::read(&mut entry.path()) {
87 Ok(value) => {
88 f(&key, Ok(value));
89 }
90 Err(e) => {
91 f(&key, Err(e));
92 }
93 }
94 }
95 }
96 }
97 }
98 Ok(())
99 }
100
101 fn iterate(kind: &mut SysFsType) -> Result<(), std::io::Error> {
102 let path: &Path = (kind).into();
103 if path.is_dir() {
104 for entry in read_dir(&path)? {
105 if let Ok(entry) = entry {
106 if entry.path().is_dir() {
107 if let Ok(link) = read_link(entry.path()) {
108 let p = Path::new(&path).join(link).canonicalize();
109 if let Ok(ref p) = p {
110 let key: String =
111 p.clone().into_os_string().to_string_lossy().into();
112 match kind {
113 SysFsType::BusUSB(map) => {
114 let mut attrs = UsbAttributes::default();
115 Self::read_generic(p, |key, value| match value {
116 Ok(value) => {
117 attrs.add(
118 key, value,
119 )
120 .unwrap_or_else(|e| {
121 log::error!(
122 "Ignored attribute: '{}' for {} cause of: {}",
123 key,
124 p.display(),
125 e
126 );
127 });
128 }
129 Err(e) => {
130 log::warn!(
131 "Could not read read USB: {}/{} cause: {}",
132 p.to_string_lossy(),
133 key,
134 e
135 );
136 }
137 })?;
138 if !attrs.descriptors.is_empty() {
139 map.insert(key, attrs);
140 }
141 }
142 SysFsType::BusPCI(map) => {
143 let mut attrs = PciAttributes::default();
144 Self::read_generic(p, |key, value| match value {
145 Ok(value) => {
146 attrs.add(key, value).unwrap();
147 }
148 Err(e) => {
149 log::warn!(
150 "Could not read read pci: {}/{} cause: {}",
151 p.to_string_lossy(),
152 key,
153 e
154 );
155 }
156 })?;
157 map.insert(key, attrs);
158 }
159 SysFsType::ClassDMI(map) => {
160 map.insert(key, Self::iterate_generic_attributes(p)?);
161 }
162 SysFsType::ClassThermal(map) => {
163 map.insert(key, Self::iterate_generic_attributes(p)?);
164 }
165 }
166 }
167 }
168 }
169 }
170 }
171 }
172 Ok(())
173 }
174
175 fn iterate_generic_attributes(p: &Path) -> Result<GenericClassAttributes, std::io::Error> {
176 let mut inner = GenericClassAttributes::default();
177 Self::read_generic(p, |key, value| match value {
178 Ok(value) => {
179 let value = String::from_utf8_lossy(&value)
180 .to_string()
181 .trim()
182 .to_string();
183 match &key[0..] {
184 "uevent" => inner.uevent = UEvent::from_str(&value).ok(),
185 _ => {
186 inner.attributes.insert(key.to_string(), value);
187 }
188 }
189 }
190 Err(e) => {
191 log::warn!("Could not read {} key: '{}' cause: {}", p.display(), key, e);
192 }
193 })?;
194 Ok(inner)
195 }
196
197 pub fn usb_devices() -> Result<UsbDevices, std::io::Error> {
199 let mut kind = SysFsType::BusUSB(UsbDevices::new());
200 Self::iterate(&mut kind)?;
201 match kind {
202 SysFsType::BusUSB(usb) => Ok(usb),
203 _ => panic!(""),
204 }
205 }
206
207 pub fn pci_devices() -> Result<PciDevices, std::io::Error> {
209 let mut kind = SysFsType::BusPCI(PciDevices::new());
210 Self::iterate(&mut kind)?;
211 match kind {
212 SysFsType::BusPCI(pci) => Ok(pci),
213 _ => panic!(""),
214 }
215 }
216
217 pub fn dmi_info() -> Result<DmiInfo, std::io::Error> {
219 let mut kind = SysFsType::ClassDMI(DmiInfo::new());
220 Self::iterate(&mut kind)?;
221 match kind {
222 SysFsType::ClassDMI(dmi) => Ok(dmi),
223 _ => panic!(""),
224 }
225 }
226
227 pub fn thermal_info() -> Result<ThermalInfo, std::io::Error> {
229 let mut kind = SysFsType::ClassThermal(ThermalInfo::new());
230 Self::iterate(&mut kind)?;
231 match kind {
232 SysFsType::ClassThermal(temp) => Ok(temp),
233 _ => panic!(""),
234 }
235 }
236}