From eb26215f2008be4b3968e19f86613aaedd8335e2 Mon Sep 17 00:00:00 2001 From: Yuki Yamaura Date: Sat, 1 Jun 2024 16:47:25 +0900 Subject: [PATCH 1/3] Add support for /dev/devices --- procfs-core/src/devices.rs | 195 +++++++++++++++++++++++++++++++++++++ procfs-core/src/lib.rs | 3 + procfs/src/lib.rs | 10 ++ support.md | 2 +- 4 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 procfs-core/src/devices.rs diff --git a/procfs-core/src/devices.rs b/procfs-core/src/devices.rs new file mode 100644 index 0000000..4576e13 --- /dev/null +++ b/procfs-core/src/devices.rs @@ -0,0 +1,195 @@ +use std::io::BufRead; + +use super::ProcResult; +use std::str::FromStr; + +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; + +/// Device entries under `/proc/devices` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[allow(non_snake_case)] +pub struct Devices { + /// Character devices + pub char_devices: Vec, + /// Block devices + pub block_devices: Vec, +} + +/// A charcter device entry under `/proc/devices` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[allow(non_snake_case)] +pub struct CharDeviceEntry { + /// Device major number + pub major: u32, + /// Device name + pub name: String, +} + +/// A block device entry under `/proc/devices` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[allow(non_snake_case)] +pub struct BlockDeviceEntry { + /// Device major number + pub major: i32, + /// Device name + pub name: String, +} + +impl super::FromBufRead for Devices { + fn from_buf_read(r: R) -> ProcResult { + enum State { + Char, + Block, + } + let mut state = State::Char; // Always start with char devices + 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); + } +} diff --git a/procfs-core/src/lib.rs b/procfs-core/src/lib.rs index c3ed24b..0c65724 100644 --- a/procfs-core/src/lib.rs +++ b/procfs-core/src/lib.rs @@ -354,6 +354,9 @@ pub use cpuinfo::*; mod crypto; pub use crypto::*; +mod devices; +pub use devices::*; + mod diskstats; pub use diskstats::*; diff --git a/procfs/src/lib.rs b/procfs/src/lib.rs index 28927a1..a1222ff 100644 --- a/procfs/src/lib.rs +++ b/procfs/src/lib.rs @@ -434,6 +434,10 @@ impl Current for CpuInfo { const PATH: &'static str = "/proc/cpuinfo"; } +impl Current for Devices { + const PATH: &'static str = "/proc/devices"; +} + impl Current for DiskStats { const PATH: &'static str = "/proc/diskstats"; } @@ -685,6 +689,12 @@ mod tests { //assert_eq!(info.num_cores(), 8); } + #[test] + fn test_devices() { + let devices = Devices::current().unwrap(); + println!("{:#?}", devices); + } + #[test] fn test_diskstats() { for disk in super::diskstats().unwrap() { diff --git a/support.md b/support.md index 3744633..5e3ff9d 100644 --- a/support.md +++ b/support.md @@ -71,7 +71,7 @@ This is an approximate list of all the files under the `/proc` mount, and an ind * [ ] `/proc/config.gz` * [ ] `/proc/crypto` * [ ] `/proc/cpuinfo` -* [ ] `/proc/devices` +* [x] `/proc/devices` * [x] `/proc/diskstats` * [ ] `/proc/dma` * [ ] `/proc/driver` From d66c910f3499860345f9903c0e8fa1683d849fb3 Mon Sep 17 00:00:00 2001 From: Yuki Yamaura Date: Wed, 7 Aug 2024 14:03:13 +0900 Subject: [PATCH 2/3] Remove unnecessary #[allow(non_snake_case)] --- procfs-core/src/devices.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/procfs-core/src/devices.rs b/procfs-core/src/devices.rs index 4576e13..ba1ee29 100644 --- a/procfs-core/src/devices.rs +++ b/procfs-core/src/devices.rs @@ -9,7 +9,6 @@ use serde::{Deserialize, Serialize}; /// Device entries under `/proc/devices` #[derive(Debug, Clone)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -#[allow(non_snake_case)] pub struct Devices { /// Character devices pub char_devices: Vec, @@ -20,7 +19,6 @@ pub struct Devices { /// A charcter device entry under `/proc/devices` #[derive(Debug, Clone)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -#[allow(non_snake_case)] pub struct CharDeviceEntry { /// Device major number pub major: u32, @@ -31,7 +29,6 @@ pub struct CharDeviceEntry { /// A block device entry under `/proc/devices` #[derive(Debug, Clone)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -#[allow(non_snake_case)] pub struct BlockDeviceEntry { /// Device major number pub major: i32, From dc70412e36060ecc4d5d600348e337ff971bd010 Mon Sep 17 00:00:00 2001 From: Yuki Yamaura Date: Wed, 7 Aug 2024 14:07:18 +0900 Subject: [PATCH 3/3] Update Devices struct doc comment to clarify block_devices can be empty --- procfs-core/src/devices.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procfs-core/src/devices.rs b/procfs-core/src/devices.rs index ba1ee29..36c4176 100644 --- a/procfs-core/src/devices.rs +++ b/procfs-core/src/devices.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; pub struct Devices { /// Character devices pub char_devices: Vec, - /// Block devices + /// Block devices, which can be empty if the kernel doesn't support block devices (without `CONFIG_BLOCK`) pub block_devices: Vec, }