Skip to content

Commit f7270aa

Browse files
committed
Add basic partition enumeration
Signed-off-by: Ikey Doherty <[email protected]>
1 parent 7d0601d commit f7270aa

File tree

4 files changed

+102
-21
lines changed

4 files changed

+102
-21
lines changed

crates/disks/src/lib.rs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use std::{
77
path::{Path, PathBuf},
88
};
99

10+
use partition::Partition;
11+
1012
pub mod nvme;
13+
pub mod partition;
1114
pub mod scsi;
1215
mod sysfs;
1316

@@ -19,6 +22,7 @@ const DEVFS_DIR: &str = "/dev";
1922
pub enum BlockDevice {
2023
/// A physical disk device
2124
Disk(Box<Disk>),
25+
Unknown,
2226
}
2327

2428
/// Represents the type of disk device.
@@ -46,23 +50,26 @@ pub struct BasicDisk {
4650
pub model: Option<String>,
4751
/// Optional disk vendor name
4852
pub vendor: Option<String>,
53+
/// Partitions
54+
pub partitions: Vec<Partition>,
4955
}
5056

5157
impl Disk {
5258
/// Returns the name of the disk device.
53-
///
54-
/// # Examples
55-
///
56-
/// ```
57-
/// // Returns strings like "sda" or "nvme0n1"
58-
/// let name = disk.name();
59-
/// ```
6059
pub fn name(&self) -> &str {
6160
match self {
6261
Disk::Scsi(disk) => disk.name(),
6362
Disk::Nvme(disk) => disk.name(),
6463
}
6564
}
65+
66+
/// Returns the partitions on the disk.
67+
pub fn partitions(&self) -> &[Partition] {
68+
match self {
69+
Disk::Scsi(disk) => disk.partitions(),
70+
Disk::Nvme(disk) => disk.partitions(),
71+
}
72+
}
6673
}
6774

6875
/// Trait for initializing different types of disk devices from sysfs.
@@ -83,12 +90,25 @@ pub(crate) trait DiskInit: Sized {
8390
impl DiskInit for BasicDisk {
8491
fn from_sysfs_path(sysroot: &Path, name: &str) -> Option<Self> {
8592
let node = sysroot.join(name);
93+
94+
// Read the partitions of the disk if any
95+
let mut partitions: Vec<_> = fs::read_dir(&node)
96+
.ok()?
97+
.filter_map(Result::ok)
98+
.filter_map(|e| {
99+
let name = e.file_name().to_string_lossy().to_string();
100+
Partition::from_sysfs_path(sysroot, &name)
101+
})
102+
.collect();
103+
partitions.sort_by_key(|p| p.number);
104+
86105
Some(Self {
87106
name: name.to_owned(),
88107
sectors: sysfs::sysfs_read(sysroot, &node, "size").unwrap_or(0),
89108
device: PathBuf::from(DEVFS_DIR).join(name),
90109
model: sysfs::sysfs_read(sysroot, &node, "device/model"),
91110
vendor: sysfs::sysfs_read(sysroot, &node, "device/vendor"),
111+
partitions,
92112
node,
93113
})
94114
}
@@ -100,15 +120,6 @@ impl BlockDevice {
100120
/// # Returns
101121
///
102122
/// A vector of discovered block devices or an IO error if the discovery fails.
103-
///
104-
/// # Examples
105-
///
106-
/// ```
107-
/// let devices = BlockDevice::discover()?;
108-
/// for device in devices {
109-
/// println!("Found device: {:?}", device);
110-
/// }
111-
/// ```
112123
pub fn discover() -> io::Result<Vec<BlockDevice>> {
113124
Self::discover_in_sysroot("/")
114125
}
@@ -157,7 +168,13 @@ mod tests {
157168
#[test]
158169
fn test_discover() {
159170
let devices = BlockDevice::discover().unwrap();
160-
assert!(!devices.is_empty());
161-
eprintln!("devices: {devices:?}");
171+
for device in &devices {
172+
if let BlockDevice::Disk(disk) = device {
173+
println!("{}:", disk.name());
174+
for partition in disk.partitions() {
175+
println!("├─{}", partition.name);
176+
}
177+
}
178+
}
162179
}
163180
}

crates/disks/src/nvme.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
//! This module provides functionality to enumerate and handle NVMe (Non-Volatile Memory Express)
88
//! storage devices by parsing sysfs paths and device names.
99
10-
use std::{path::Path, sync::OnceLock};
10+
use crate::{partition::Partition, BasicDisk, DiskInit};
1111
use regex::Regex;
12-
use crate::{BasicDisk, DiskInit};
12+
use std::{path::Path, sync::OnceLock};
1313

1414
/// Regex pattern to match valid NVMe device names (e.g. nvme0n1)
1515
static NVME_PATTERN: OnceLock<Regex> = OnceLock::new();
@@ -52,4 +52,9 @@ impl Disk {
5252
pub fn name(&self) -> &str {
5353
&self.disk.name
5454
}
55+
56+
/// Returns the partitions on the disk
57+
pub fn partitions(&self) -> &[Partition] {
58+
&self.disk.partitions
59+
}
5560
}

crates/disks/src/partition.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-FileCopyrightText: Copyright © 2025 Serpent OS Developers
2+
//
3+
// SPDX-License-Identifier: MPL-2.0
4+
5+
use std::path::{Path, PathBuf};
6+
7+
use crate::{sysfs::sysfs_read, DEVFS_DIR, SYSFS_DIR};
8+
9+
/// Represents a partition on a disk device
10+
/// - Size in sectors
11+
#[derive(Debug)]
12+
pub struct Partition {
13+
/// Name of the partition
14+
pub name: String,
15+
/// Partition number on the disk
16+
pub number: u32,
17+
/// Starting sector of the partition
18+
pub start: u64,
19+
/// Ending sector of the partition
20+
pub end: u64,
21+
/// Size of partition in sectors
22+
pub size: u64,
23+
/// Path to the partition node in sysfs
24+
pub node: PathBuf,
25+
/// Path to the partition device in /dev
26+
pub device: PathBuf,
27+
}
28+
29+
impl Partition {
30+
/// Creates a new Partition instance from a sysfs path and partition name.
31+
///
32+
/// # Arguments
33+
/// * `sysroot` - Base path to sysfs
34+
/// * `name` - Name of the partition
35+
///
36+
/// # Returns
37+
/// * `Some(Partition)` if partition exists and is valid
38+
/// * `None` if partition doesn't exist or is invalid
39+
pub fn from_sysfs_path(sysroot: &Path, name: &str) -> Option<Self> {
40+
let node = sysroot.join(SYSFS_DIR).join(name);
41+
let partition_no: u32 = sysfs_read(sysroot, &node, "partition")?;
42+
let start = sysfs_read(sysroot, &node, "start")?;
43+
let size = sysfs_read(sysroot, &node, "size")?;
44+
Some(Self {
45+
name: name.to_owned(),
46+
number: partition_no,
47+
start,
48+
size,
49+
end: start + size,
50+
node,
51+
device: sysroot.join(DEVFS_DIR).join(name),
52+
})
53+
}
54+
}

crates/disks/src/scsi.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
1111
use std::path::Path;
1212

13-
use crate::{BasicDisk, DiskInit};
13+
use crate::{partition::Partition, BasicDisk, DiskInit};
1414

1515
/// Represents a SCSI disk device.
1616
///
@@ -53,4 +53,9 @@ impl Disk {
5353
pub fn name(&self) -> &str {
5454
&self.disk.name
5555
}
56+
57+
/// Returns the partitions on the disk.
58+
pub fn partitions(&self) -> &[Partition] {
59+
&self.disk.partitions
60+
}
5661
}

0 commit comments

Comments
 (0)