use std::io::BufRead;
use super::ProcResult;
use std::str::FromStr;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Devices {
pub char_devices: Vec<CharDeviceEntry>,
pub block_devices: Vec<BlockDeviceEntry>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct CharDeviceEntry {
pub major: u32,
pub name: String,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct BlockDeviceEntry {
pub major: i32,
pub name: String,
}
impl super::FromBufRead for Devices {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
enum State {
Char,
Block,
}
let mut state = State::Char; let mut devices = Devices {
char_devices: vec![],
block_devices: vec![],
};
for line in r.lines() {
let line = expect!(line);
if line.is_empty() {
continue;
} else if line.starts_with("Character devices:") {
state = State::Char;
continue;
} else if line.starts_with("Block devices:") {
state = State::Block;
continue;
}
let mut s = line.split_whitespace();
match state {
State::Char => {
let major = expect!(u32::from_str(expect!(s.next())));
let name = expect!(s.next()).to_string();
let char_device_entry = CharDeviceEntry { major, name };
devices.char_devices.push(char_device_entry);
}
State::Block => {
let major = expect!(i32::from_str(expect!(s.next())));
let name = expect!(s.next()).to_string();
let block_device_entry = BlockDeviceEntry { major, name };
devices.block_devices.push(block_device_entry);
}
}
}
Ok(devices)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_devices() {
use crate::FromBufRead;
use std::io::Cursor;
let s = "Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
90 mtd
136 pts
180 usb
188 ttyUSB
189 usb_device
Block devices:
7 loop
8 sd
65 sd
71 sd
128 sd
135 sd
254 device-mapper
259 blkext
";
let cursor = Cursor::new(s);
let devices = Devices::from_buf_read(cursor).unwrap();
let (chrs, blks) = (devices.char_devices, devices.block_devices);
assert_eq!(chrs.len(), 16);
assert_eq!(chrs[1].major, 4);
assert_eq!(chrs[1].name, "/dev/vc/0");
assert_eq!(chrs[8].major, 10);
assert_eq!(chrs[8].name, "misc");
assert_eq!(chrs[15].major, 189);
assert_eq!(chrs[15].name, "usb_device");
assert_eq!(blks.len(), 8);
assert_eq!(blks[0].major, 7);
assert_eq!(blks[0].name, "loop");
assert_eq!(blks[7].major, 259);
assert_eq!(blks[7].name, "blkext");
}
#[test]
fn test_devices_without_block() {
use crate::FromBufRead;
use std::io::Cursor;
let s = "Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
90 mtd
136 pts
180 usb
188 ttyUSB
189 usb_device
";
let cursor = Cursor::new(s);
let devices = Devices::from_buf_read(cursor).unwrap();
let (chrs, blks) = (devices.char_devices, devices.block_devices);
assert_eq!(chrs.len(), 16);
assert_eq!(chrs[1].major, 4);
assert_eq!(chrs[1].name, "/dev/vc/0");
assert_eq!(chrs[8].major, 10);
assert_eq!(chrs[8].name, "misc");
assert_eq!(chrs[15].major, 189);
assert_eq!(chrs[15].name, "usb_device");
assert_eq!(blks.len(), 0);
}
}