Skip to content

Commit

Permalink
Add support for /dev/devices
Browse files Browse the repository at this point in the history
  • Loading branch information
yamaura committed Aug 7, 2024
1 parent 784dd2c commit eb26215
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 1 deletion.
195 changes: 195 additions & 0 deletions procfs-core/src/devices.rs
Original file line number Diff line number Diff line change
@@ -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<CharDeviceEntry>,
/// Block devices
pub block_devices: Vec<BlockDeviceEntry>,
}

/// 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: BufRead>(r: R) -> ProcResult<Self> {
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);
}
}
3 changes: 3 additions & 0 deletions procfs-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ pub use cpuinfo::*;
mod crypto;
pub use crypto::*;

mod devices;
pub use devices::*;

mod diskstats;
pub use diskstats::*;

Expand Down
10 changes: 10 additions & 0 deletions procfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion support.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down

0 comments on commit eb26215

Please sign in to comment.