1use std::io::BufRead;
2
3use super::ProcResult;
4use std::str::FromStr;
5
6#[cfg(feature = "serde1")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone)]
11#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
12pub struct Devices {
13 pub char_devices: Vec<CharDeviceEntry>,
15 pub block_devices: Vec<BlockDeviceEntry>,
17}
18
19#[derive(Debug, Clone)]
21#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
22pub struct CharDeviceEntry {
23 pub major: u32,
25 pub name: String,
27}
28
29#[derive(Debug, Clone)]
31#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
32pub struct BlockDeviceEntry {
33 pub major: i32,
35 pub name: String,
37}
38
39impl super::FromBufRead for Devices {
40 fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
41 enum State {
42 Char,
43 Block,
44 }
45 let mut state = State::Char; let mut devices = Devices {
47 char_devices: vec![],
48 block_devices: vec![],
49 };
50
51 for line in r.lines() {
52 let line = expect!(line);
53
54 if line.is_empty() {
55 continue;
56 } else if line.starts_with("Character devices:") {
57 state = State::Char;
58 continue;
59 } else if line.starts_with("Block devices:") {
60 state = State::Block;
61 continue;
62 }
63
64 let mut s = line.split_whitespace();
65
66 match state {
67 State::Char => {
68 let major = expect!(u32::from_str(expect!(s.next())));
69 let name = expect!(s.next()).to_string();
70
71 let char_device_entry = CharDeviceEntry { major, name };
72
73 devices.char_devices.push(char_device_entry);
74 }
75 State::Block => {
76 let major = expect!(i32::from_str(expect!(s.next())));
77 let name = expect!(s.next()).to_string();
78
79 let block_device_entry = BlockDeviceEntry { major, name };
80
81 devices.block_devices.push(block_device_entry);
82 }
83 }
84 }
85
86 Ok(devices)
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 #[test]
94 fn test_devices() {
95 use crate::FromBufRead;
96 use std::io::Cursor;
97
98 let s = "Character devices:
99 1 mem
100 4 /dev/vc/0
101 4 tty
102 4 ttyS
103 5 /dev/tty
104 5 /dev/console
105 5 /dev/ptmx
106 7 vcs
107 10 misc
108 13 input
109 29 fb
110 90 mtd
111136 pts
112180 usb
113188 ttyUSB
114189 usb_device
115
116Block devices:
117 7 loop
118 8 sd
119 65 sd
120 71 sd
121128 sd
122135 sd
123254 device-mapper
124259 blkext
125";
126
127 let cursor = Cursor::new(s);
128 let devices = Devices::from_buf_read(cursor).unwrap();
129 let (chrs, blks) = (devices.char_devices, devices.block_devices);
130
131 assert_eq!(chrs.len(), 16);
132
133 assert_eq!(chrs[1].major, 4);
134 assert_eq!(chrs[1].name, "/dev/vc/0");
135
136 assert_eq!(chrs[8].major, 10);
137 assert_eq!(chrs[8].name, "misc");
138
139 assert_eq!(chrs[15].major, 189);
140 assert_eq!(chrs[15].name, "usb_device");
141
142 assert_eq!(blks.len(), 8);
143
144 assert_eq!(blks[0].major, 7);
145 assert_eq!(blks[0].name, "loop");
146
147 assert_eq!(blks[7].major, 259);
148 assert_eq!(blks[7].name, "blkext");
149 }
150
151 #[test]
152 fn test_devices_without_block() {
153 use crate::FromBufRead;
154 use std::io::Cursor;
155
156 let s = "Character devices:
157 1 mem
158 4 /dev/vc/0
159 4 tty
160 4 ttyS
161 5 /dev/tty
162 5 /dev/console
163 5 /dev/ptmx
164 7 vcs
165 10 misc
166 13 input
167 29 fb
168 90 mtd
169136 pts
170180 usb
171188 ttyUSB
172189 usb_device
173";
174
175 let cursor = Cursor::new(s);
176 let devices = Devices::from_buf_read(cursor).unwrap();
177 let (chrs, blks) = (devices.char_devices, devices.block_devices);
178
179 assert_eq!(chrs.len(), 16);
180
181 assert_eq!(chrs[1].major, 4);
182 assert_eq!(chrs[1].name, "/dev/vc/0");
183
184 assert_eq!(chrs[8].major, 10);
185 assert_eq!(chrs[8].name, "misc");
186
187 assert_eq!(chrs[15].major, 189);
188 assert_eq!(chrs[15].name, "usb_device");
189
190 assert_eq!(blks.len(), 0);
191 }
192}