1use std::ffi::OsString;
2use std::fs::read_dir;
3use std::fs::read_to_string;
4use std::io::Error as IoError;
5
6#[derive(Debug, Clone)]
7pub struct StorageDevice {
8 pub name: String,
9 pub capacity: usize,
10 pub partitions: Vec<Partition>,
11 pub read_only: bool,
12}
13
14#[derive(Debug, Clone)]
15pub struct Partition {
16 pub name: String,
17 pub capacity: usize,
18 pub read_only: bool,
19}
20
21fn read_prop(base: &str, prop: &str) -> Option<String> {
22 let value = read_to_string(format!("{}/{}", base, prop)).ok()?;
23 Some(String::from(&value[..value.len() - 1]))
24}
25
26fn read_partition(device: &str, entry: OsString, sector_size: usize) -> Option<Partition> {
27 let name = entry.into_string().ok()?;
28 let path = format!("/sys/block/{}/{}", device, name);
29 let sectors = read_prop(&path, "size")?.parse::<usize>().ok()?;
30 let read_only = read_prop(&path, "ro")? == "1";
31 Some(Partition {
32 name,
33 capacity: sectors * sector_size,
34 read_only,
35 })
36}
37
38fn read_device(entry: OsString) -> Option<StorageDevice> {
39 let name = entry.into_string().ok()?;
40 let path = format!("/sys/block/{}", name);
41 let sectors = read_prop(&path, "size")?.parse::<usize>().ok()?;
42 let sector_size = read_prop(&path, "queue/hw_sector_size")?.parse().ok()?;
43 let read_only = read_prop(&path, "ro")? == "1";
44 let mut partitions = Vec::new();
45 for entry in read_dir(&path).ok()? {
46 if let Some(partition) = read_partition(&name, entry.ok()?.file_name(), sector_size) {
47 partitions.push(partition);
48 }
49 }
50 Some(StorageDevice {
51 name,
52 capacity: sectors * sector_size,
53 partitions,
54 read_only,
55 })
56}
57
58pub fn list_partitions() -> Result<Vec<StorageDevice>, IoError> {
59 let mut devices = Vec::new();
60 for entry in read_dir("/sys/block")? {
61 if let Some(device) = read_device(entry?.file_name()) {
62 devices.push(device);
63 }
64 }
65 Ok(devices)
66}