use std::fs::File;
use std::io::{BufReader, BufRead};
pub fn devices() -> std::io::Result<impl Iterator<Item = Device>> {
Ok(parse_devices(BufReader::new(File::open("/proc/devices")?)))
}
#[derive(Clone)]
#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq, Eq)]
pub enum DeviceKind {
Character,
Block,
}
#[derive(Debug)]
#[derive(PartialEq, Eq)]
pub struct Device {
pub kind: DeviceKind,
pub major: u32,
pub driver: String,
}
impl Device {
pub fn parse(kind: DeviceKind, line: String) -> Option<Device> {
let mut major = String::new();
let mut driver = String::new();
let mut major_done = false;
for c in line.chars() {
if major_done {
if c.is_ascii_alphanumeric() {
driver.push(c);
}
} else {
if c.is_digit(10) {
major.push(c);
} else if major.len() > 0 {
major_done = true;
}
}
}
if major.len() > 0 && driver.len() > 0 {
match major.parse::<u32>() {
Ok(major_number) => Some(Device {
kind: kind,
major: major_number,
driver: driver,
}),
Err(_) => None
}
} else {
None
}
}
}
fn parse_device_line(current_kind: &mut DeviceKind, line: String) -> Option<Option<Device>> {
if line == "Character devices:" {
*current_kind = DeviceKind::Character;
Some(None)
} else if line == "Block devices:" {
*current_kind = DeviceKind::Block;
Some(None)
} else {
Some(Device::parse(*current_kind, line))
}
}
pub fn parse_devices(input: impl BufRead) -> impl Iterator<Item = Device> {
input
.lines()
.map(|result| result.unwrap())
.scan(DeviceKind::Character, parse_device_line)
.flat_map(|x| x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_devices() {
let input = "
Character devices:
1 mem
4 tty
249 rtc
Block devices:
7 loop
9 md
";
let mut devices = parse_devices(std::io::Cursor::new(input));
assert_eq!(devices.next(), Some(Device { kind: DeviceKind::Character, major: 1, driver: String::from("mem") }));
assert_eq!(devices.next(), Some(Device { kind: DeviceKind::Character, major: 4, driver: String::from("tty") }));
assert_eq!(devices.next(), Some(Device { kind: DeviceKind::Character, major: 249, driver: String::from("rtc") }));
assert_eq!(devices.next(), Some(Device { kind: DeviceKind::Block, major: 7, driver: String::from("loop") }));
assert_eq!(devices.next(), Some(Device { kind: DeviceKind::Block, major: 9, driver: String::from("md") }));
assert_eq!(devices.next(), None);
}
}