Skip to content

Commit 9a58693

Browse files
authored
Merge pull request #1050 from cgwalters/blockdev-crate
Split off a blockdev internal crate
2 parents b086321 + 4f3e556 commit 9a58693

File tree

9 files changed

+102
-68
lines changed

9 files changed

+102
-68
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["cli", "lib", "ostree-ext", "xtask", "tests-integration"]
2+
members = ["cli", "lib", "ostree-ext", "blockdev", "xtask", "tests-integration"]
33
resolver = "2"
44

55
[profile.dev]

blockdev/Cargo.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
description = "Internal blockdev code"
3+
# Should never be published to crates.io
4+
publish = false
5+
edition = "2021"
6+
license = "MIT OR Apache-2.0"
7+
name = "blockdev"
8+
repository = "https://github.com/containers/bootc"
9+
version = "0.0.0"
10+
11+
[dependencies]
12+
anyhow = { workspace = true }
13+
bootc-utils = { path = "../utils" }
14+
camino = { workspace = true, features = ["serde1"] }
15+
fn-error-context = { workspace = true }
16+
regex = "1.10.4"
17+
serde = { workspace = true, features = ["derive"] }
18+
serde_json = { workspace = true }
19+
tracing = { workspace = true }
20+
21+
[dev-dependencies]
22+
indoc = "2.0.5"
23+
24+
[lib]
25+
path = "src/blockdev.rs"

lib/src/blockdev.rs renamed to blockdev/src/blockdev.rs

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
use std::collections::HashMap;
2-
#[cfg(feature = "install-to-disk")]
32
use std::env;
4-
#[cfg(feature = "install-to-disk")]
53
use std::path::Path;
64
use std::process::Command;
75
use std::sync::OnceLock;
86

97
use anyhow::{anyhow, Context, Result};
108
use camino::Utf8Path;
11-
#[cfg(feature = "install-to-disk")]
129
use camino::Utf8PathBuf;
1310
use fn_error_context::context;
1411
use regex::Regex;
@@ -23,34 +20,34 @@ struct DevicesOutput {
2320

2421
#[allow(dead_code)]
2522
#[derive(Debug, Deserialize)]
26-
pub(crate) struct Device {
27-
pub(crate) name: String,
28-
pub(crate) serial: Option<String>,
29-
pub(crate) model: Option<String>,
30-
pub(crate) partlabel: Option<String>,
31-
pub(crate) children: Option<Vec<Device>>,
32-
pub(crate) size: u64,
23+
pub struct Device {
24+
pub name: String,
25+
pub serial: Option<String>,
26+
pub model: Option<String>,
27+
pub partlabel: Option<String>,
28+
pub children: Option<Vec<Device>>,
29+
pub size: u64,
3330
#[serde(rename = "maj:min")]
34-
pub(crate) maj_min: Option<String>,
31+
pub maj_min: Option<String>,
3532
// NOTE this one is not available on older util-linux, and
3633
// will also not exist for whole blockdevs (as opposed to partitions).
37-
pub(crate) start: Option<u64>,
34+
pub start: Option<u64>,
3835

3936
// Filesystem-related properties
40-
pub(crate) label: Option<String>,
41-
pub(crate) fstype: Option<String>,
42-
pub(crate) path: Option<String>,
37+
pub label: Option<String>,
38+
pub fstype: Option<String>,
39+
pub path: Option<String>,
4340
}
4441

4542
impl Device {
4643
#[allow(dead_code)]
4744
// RHEL8's lsblk doesn't have PATH, so we do it
48-
pub(crate) fn path(&self) -> String {
45+
pub fn path(&self) -> String {
4946
self.path.clone().unwrap_or(format!("/dev/{}", &self.name))
5047
}
5148

5249
#[allow(dead_code)]
53-
pub(crate) fn has_children(&self) -> bool {
50+
pub fn has_children(&self) -> bool {
5451
self.children.as_ref().map_or(false, |v| !v.is_empty())
5552
}
5653

@@ -77,7 +74,7 @@ impl Device {
7774
}
7875

7976
/// Older versions of util-linux may be missing some properties. Backfill them if they're missing.
80-
pub(crate) fn backfill_missing(&mut self) -> Result<()> {
77+
pub fn backfill_missing(&mut self) -> Result<()> {
8178
// Add new properties to backfill here
8279
self.backfill_start()?;
8380
// And recurse to child devices
@@ -89,7 +86,7 @@ impl Device {
8986
}
9087

9188
#[context("Listing device {dev}")]
92-
pub(crate) fn list_dev(dev: &Utf8Path) -> Result<Device> {
89+
pub fn list_dev(dev: &Utf8Path) -> Result<Device> {
9390
let mut devs: DevicesOutput = Command::new("lsblk")
9491
.args(["-J", "-b", "-O"])
9592
.arg(dev)
@@ -111,52 +108,52 @@ struct SfDiskOutput {
111108

112109
#[derive(Debug, Deserialize)]
113110
#[allow(dead_code)]
114-
pub(crate) struct Partition {
115-
pub(crate) node: String,
116-
pub(crate) start: u64,
117-
pub(crate) size: u64,
111+
pub struct Partition {
112+
pub node: String,
113+
pub start: u64,
114+
pub size: u64,
118115
#[serde(rename = "type")]
119-
pub(crate) parttype: String,
120-
pub(crate) uuid: Option<String>,
121-
pub(crate) name: Option<String>,
116+
pub parttype: String,
117+
pub uuid: Option<String>,
118+
pub name: Option<String>,
122119
}
123120

124121
#[derive(Debug, Deserialize, PartialEq, Eq)]
125122
#[serde(rename_all = "kebab-case")]
126-
pub(crate) enum PartitionType {
123+
pub enum PartitionType {
127124
Dos,
128125
Gpt,
129126
Unknown(String),
130127
}
131128

132129
#[derive(Debug, Deserialize)]
133130
#[allow(dead_code)]
134-
pub(crate) struct PartitionTable {
135-
pub(crate) label: PartitionType,
136-
pub(crate) id: String,
137-
pub(crate) device: String,
131+
pub struct PartitionTable {
132+
pub label: PartitionType,
133+
pub id: String,
134+
pub device: String,
138135
// We're not using these fields
139-
// pub(crate) unit: String,
140-
// pub(crate) firstlba: u64,
141-
// pub(crate) lastlba: u64,
142-
// pub(crate) sectorsize: u64,
143-
pub(crate) partitions: Vec<Partition>,
136+
// pub unit: String,
137+
// pub firstlba: u64,
138+
// pub lastlba: u64,
139+
// pub sectorsize: u64,
140+
pub partitions: Vec<Partition>,
144141
}
145142

146143
impl PartitionTable {
147144
/// Find the partition with the given device name
148145
#[allow(dead_code)]
149-
pub(crate) fn find<'a>(&'a self, devname: &str) -> Option<&'a Partition> {
146+
pub fn find<'a>(&'a self, devname: &str) -> Option<&'a Partition> {
150147
self.partitions.iter().find(|p| p.node.as_str() == devname)
151148
}
152149

153-
pub(crate) fn path(&self) -> &Utf8Path {
150+
pub fn path(&self) -> &Utf8Path {
154151
self.device.as_str().into()
155152
}
156153

157154
// Find the partition with the given offset (starting at 1)
158155
#[allow(dead_code)]
159-
pub(crate) fn find_partno(&self, partno: u32) -> Result<&Partition> {
156+
pub fn find_partno(&self, partno: u32) -> Result<&Partition> {
160157
let r = self
161158
.partitions
162159
.get(partno.checked_sub(1).expect("1 based partition offset") as usize)
@@ -167,28 +164,26 @@ impl PartitionTable {
167164

168165
impl Partition {
169166
#[allow(dead_code)]
170-
pub(crate) fn path(&self) -> &Utf8Path {
167+
pub fn path(&self) -> &Utf8Path {
171168
self.node.as_str().into()
172169
}
173170
}
174171

175172
#[context("Listing partitions of {dev}")]
176-
pub(crate) fn partitions_of(dev: &Utf8Path) -> Result<PartitionTable> {
173+
pub fn partitions_of(dev: &Utf8Path) -> Result<PartitionTable> {
177174
let o: SfDiskOutput = Command::new("sfdisk")
178175
.args(["-J", dev.as_str()])
179176
.run_and_parse_json()?;
180177
Ok(o.partitiontable)
181178
}
182179

183-
#[cfg(feature = "install-to-disk")]
184-
pub(crate) struct LoopbackDevice {
185-
pub(crate) dev: Option<Utf8PathBuf>,
180+
pub struct LoopbackDevice {
181+
pub dev: Option<Utf8PathBuf>,
186182
}
187183

188-
#[cfg(feature = "install-to-disk")]
189184
impl LoopbackDevice {
190185
// Create a new loopback block device targeting the provided file path.
191-
pub(crate) fn new(path: &Path) -> Result<Self> {
186+
pub fn new(path: &Path) -> Result<Self> {
192187
let direct_io = match env::var("BOOTC_DIRECT_IO") {
193188
Ok(val) => {
194189
if val == "on" {
@@ -215,7 +210,7 @@ impl LoopbackDevice {
215210
}
216211

217212
// Access the path to the loopback block device.
218-
pub(crate) fn path(&self) -> &Utf8Path {
213+
pub fn path(&self) -> &Utf8Path {
219214
// SAFETY: The option cannot be destructured until we are dropped
220215
self.dev.as_deref().unwrap()
221216
}
@@ -231,12 +226,11 @@ impl LoopbackDevice {
231226
}
232227

233228
/// Consume this device, unmounting it.
234-
pub(crate) fn close(mut self) -> Result<()> {
229+
pub fn close(mut self) -> Result<()> {
235230
self.impl_close()
236231
}
237232
}
238233

239-
#[cfg(feature = "install-to-disk")]
240234
impl Drop for LoopbackDevice {
241235
fn drop(&mut self) {
242236
// Best effort to unmount if we're dropped without invoking `close`
@@ -259,7 +253,7 @@ fn split_lsblk_line(line: &str) -> HashMap<String, String> {
259253
/// This is a bit fuzzy, but... this function will return every block device in the parent
260254
/// hierarchy of `device` capable of containing other partitions. So e.g. parent devices of type
261255
/// "part" doesn't match, but "disk" and "mpath" does.
262-
pub(crate) fn find_parent_devices(device: &str) -> Result<Vec<String>> {
256+
pub fn find_parent_devices(device: &str) -> Result<Vec<String>> {
263257
let output = Command::new("lsblk")
264258
// Older lsblk, e.g. in CentOS 7.6, doesn't support PATH, but --paths option
265259
.arg("--pairs")
@@ -291,8 +285,7 @@ pub(crate) fn find_parent_devices(device: &str) -> Result<Vec<String>> {
291285
}
292286

293287
/// Parse a string into mibibytes
294-
#[cfg(feature = "install-to-disk")]
295-
pub(crate) fn parse_size_mib(mut s: &str) -> Result<u64> {
288+
pub fn parse_size_mib(mut s: &str) -> Result<u64> {
296289
let suffixes = [
297290
("MiB", 1u64),
298291
("M", 1u64),

lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ anstream = "0.6.13"
1717
anstyle = "1.0.6"
1818
anyhow = { workspace = true }
1919
bootc-utils = { path = "../utils" }
20+
bootc-blockdev = { path = "../blockdev", package = "blockdev" }
2021
camino = { workspace = true, features = ["serde1"] }
2122
ostree-ext = { path = "../ostree-ext" }
2223
chrono = { workspace = true, features = ["serde"] }

lib/src/bootloader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use anyhow::{anyhow, bail, Context, Result};
22
use camino::{Utf8Path, Utf8PathBuf};
33
use fn_error_context::context;
44

5-
use crate::blockdev::PartitionTable;
65
use crate::task::Task;
6+
use bootc_blockdev::PartitionTable;
77

88
/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
99
pub(crate) const EFI_DIR: &str = "efi";
@@ -69,7 +69,7 @@ pub(crate) fn install_via_zipl(device: &PartitionTable, boot_uuid: &str) -> Resu
6969
// Ensure that the found partition is a part of the target device
7070
let device_path = device.path();
7171

72-
let partitions = crate::blockdev::list_dev(device_path)?
72+
let partitions = bootc_blockdev::list_dev(device_path)?
7373
.children
7474
.with_context(|| format!("no partition found on {device_path}"))?;
7575
let boot_part = partitions

lib/src/install.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> {
884884
pub(crate) struct RootSetup {
885885
#[cfg(feature = "install-to-disk")]
886886
luks_device: Option<String>,
887-
device_info: crate::blockdev::PartitionTable,
887+
device_info: bootc_blockdev::PartitionTable,
888888
/// Absolute path to the location where we've mounted the physical
889889
/// root filesystem for the system we're installing.
890890
physical_root_path: Utf8PathBuf,
@@ -1398,13 +1398,13 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
13981398
let rootfs = &*rootfs;
13991399

14001400
match &rootfs.device_info.label {
1401-
crate::blockdev::PartitionType::Dos => crate::utils::medium_visibility_warning(
1401+
bootc_blockdev::PartitionType::Dos => crate::utils::medium_visibility_warning(
14021402
"Installing to `dos` format partitions is not recommended",
14031403
),
1404-
crate::blockdev::PartitionType::Gpt => {
1404+
bootc_blockdev::PartitionType::Gpt => {
14051405
// The only thing we should be using in general
14061406
}
1407-
crate::blockdev::PartitionType::Unknown(o) => {
1407+
bootc_blockdev::PartitionType::Unknown(o) => {
14081408
crate::utils::medium_visibility_warning(&format!("Unknown partition label {o}"))
14091409
}
14101410
}
@@ -1480,7 +1480,7 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
14801480
let (mut rootfs, loopback) = {
14811481
let loopback_dev = if opts.via_loopback {
14821482
let loopback_dev =
1483-
crate::blockdev::LoopbackDevice::new(block_opts.device.as_std_path())?;
1483+
bootc_blockdev::LoopbackDevice::new(block_opts.device.as_std_path())?;
14841484
block_opts.device = loopback_dev.path().into();
14851485
Some(loopback_dev)
14861486
} else {
@@ -1811,7 +1811,7 @@ pub(crate) async fn install_to_filesystem(
18111811
let mut dev = inspect.source;
18121812
loop {
18131813
tracing::debug!("Finding parents for {dev}");
1814-
let mut parents = crate::blockdev::find_parent_devices(&dev)?.into_iter();
1814+
let mut parents = bootc_blockdev::find_parent_devices(&dev)?.into_iter();
18151815
let Some(parent) = parents.next() else {
18161816
break;
18171817
};
@@ -1825,7 +1825,7 @@ pub(crate) async fn install_to_filesystem(
18251825
dev
18261826
};
18271827
tracing::debug!("Backing device: {backing_device}");
1828-
let device_info = crate::blockdev::partitions_of(Utf8Path::new(&backing_device))?;
1828+
let device_info = bootc_blockdev::partitions_of(Utf8Path::new(&backing_device))?;
18291829

18301830
let rootarg = format!("root={}", root_info.mount_spec);
18311831
let mut boot = if let Some(spec) = fsopts.boot_mount_spec {

0 commit comments

Comments
 (0)