commit
9f5f567d90
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1043,6 +1043,7 @@ dependencies = [
|
|||||||
"rlimit",
|
"rlimit",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
|
"uu_blockdev",
|
||||||
"uu_ctrlaltdel",
|
"uu_ctrlaltdel",
|
||||||
"uu_dmesg",
|
"uu_dmesg",
|
||||||
"uu_fsfreeze",
|
"uu_fsfreeze",
|
||||||
@ -1056,6 +1057,17 @@ dependencies = [
|
|||||||
"xattr",
|
"xattr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uu_blockdev"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"linux-raw-sys 0.7.0",
|
||||||
|
"regex",
|
||||||
|
"sysinfo",
|
||||||
|
"uucore",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uu_ctrlaltdel"
|
name = "uu_ctrlaltdel"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -26,6 +26,7 @@ default = ["feat_common_core"]
|
|||||||
uudoc = []
|
uudoc = []
|
||||||
|
|
||||||
feat_common_core = [
|
feat_common_core = [
|
||||||
|
"blockdev",
|
||||||
"ctrlaltdel",
|
"ctrlaltdel",
|
||||||
"dmesg",
|
"dmesg",
|
||||||
"fsfreeze",
|
"fsfreeze",
|
||||||
@ -67,6 +68,7 @@ phf = { workspace = true }
|
|||||||
textwrap = { workspace = true }
|
textwrap = { workspace = true }
|
||||||
uucore = { workspace = true }
|
uucore = { workspace = true }
|
||||||
|
|
||||||
|
blockdev = { optional = true, version = "0.0.1", package = "uu_blockdev", path = "src/uu/blockdev" }
|
||||||
ctrlaltdel = { optional = true, version = "0.0.1", package = "uu_ctrlaltdel", path = "src/uu/ctrlaltdel" }
|
ctrlaltdel = { optional = true, version = "0.0.1", package = "uu_ctrlaltdel", path = "src/uu/ctrlaltdel" }
|
||||||
dmesg = { optional = true, version = "0.0.1", package = "uu_dmesg", path = "src/uu/dmesg" }
|
dmesg = { optional = true, version = "0.0.1", package = "uu_dmesg", path = "src/uu/dmesg" }
|
||||||
fsfreeze = { optional = true, version = "0.0.1", package = "uu_fsfreeze", path = "src/uu/fsfreeze" }
|
fsfreeze = { optional = true, version = "0.0.1", package = "uu_fsfreeze", path = "src/uu/fsfreeze" }
|
||||||
|
19
src/uu/blockdev/Cargo.toml
Normal file
19
src/uu/blockdev/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "uu_blockdev"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
description = "blockdev ~ Get or set various block device attributes."
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/blockdev.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "blockdev"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { workspace = true }
|
||||||
|
linux-raw-sys = { workspace = true }
|
||||||
|
regex = { workspace = true }
|
||||||
|
sysinfo = { workspace = true }
|
||||||
|
uucore = { workspace = true }
|
8
src/uu/blockdev/blockdev.md
Normal file
8
src/uu/blockdev/blockdev.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# blockdev
|
||||||
|
|
||||||
|
```
|
||||||
|
blockdev <COMMAND...> <DEVICE...>
|
||||||
|
blockdev --report <DEVICE...>
|
||||||
|
```
|
||||||
|
|
||||||
|
Get or set various block device attributes.
|
432
src/uu/blockdev/src/blockdev.rs
Normal file
432
src/uu/blockdev/src/blockdev.rs
Normal file
@ -0,0 +1,432 @@
|
|||||||
|
// This file is part of the uutils util-linux package.
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
|
use clap::{crate_version, value_parser, Arg, ArgAction, Command};
|
||||||
|
use linux_raw_sys::ioctl::*;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use uucore::error::USimpleError;
|
||||||
|
use uucore::{error::UResult, format_usage, help_about, help_usage};
|
||||||
|
|
||||||
|
const ABOUT: &str = help_about!("blockdev.md");
|
||||||
|
const USAGE: &str = help_usage!("blockdev.md");
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
enum IoctlArgType {
|
||||||
|
Short,
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
U64Sectors,
|
||||||
|
U64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum IoctlCommand {
|
||||||
|
GetAttribute(IoctlArgType),
|
||||||
|
SetAttribute,
|
||||||
|
Operation(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum BlockdevCommand {
|
||||||
|
SetVerbosity(bool),
|
||||||
|
Ioctl(&'static str, u32, IoctlCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
const BLOCKDEV_ACTIONS: &[(&str, BlockdevCommand)] = &[
|
||||||
|
("verbose", BlockdevCommand::SetVerbosity(true)),
|
||||||
|
("quiet", BlockdevCommand::SetVerbosity(false)),
|
||||||
|
(
|
||||||
|
"flushbufs",
|
||||||
|
BlockdevCommand::Ioctl("flush buffers", BLKFLSBUF, IoctlCommand::Operation(0)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getalignoff",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get alignment offset in bytes",
|
||||||
|
BLKALIGNOFF,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getbsz",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get blocksize",
|
||||||
|
BLKBSZGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getdiscardzeroes",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get discard zeroes support status",
|
||||||
|
BLKDISCARDZEROES,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getfra",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get filesystem readahead",
|
||||||
|
BLKFRAGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Long),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getiomin",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get minimum I/O size",
|
||||||
|
BLKIOMIN,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getioopt",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get optimal I/O size",
|
||||||
|
BLKIOOPT,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getmaxsect",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get max sectors per request",
|
||||||
|
BLKSECTGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Short),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getpbsz",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get physical block (sector) size",
|
||||||
|
BLKPBSZGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getra",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get readahead",
|
||||||
|
BLKRAGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Long),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getro",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get read-only",
|
||||||
|
BLKROGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getsize64",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get size in bytes",
|
||||||
|
BLKGETSIZE64,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::U64),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getsize",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get 32-bit sector count (deprecated, use --getsz)",
|
||||||
|
BLKGETSIZE,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Long),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getss",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get logical block (sector) size",
|
||||||
|
BLKSSZGET,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::Int),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"getsz",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"get size in 512-byte sectors",
|
||||||
|
BLKGETSIZE64,
|
||||||
|
IoctlCommand::GetAttribute(IoctlArgType::U64Sectors),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"rereadpt",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"reread partition table",
|
||||||
|
BLKRRPART,
|
||||||
|
IoctlCommand::Operation(0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"setbsz",
|
||||||
|
BlockdevCommand::Ioctl("set blocksize", BLKBSZSET, IoctlCommand::SetAttribute),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"setfra",
|
||||||
|
BlockdevCommand::Ioctl(
|
||||||
|
"set filesystem readahead",
|
||||||
|
BLKFRASET,
|
||||||
|
IoctlCommand::SetAttribute,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"setra",
|
||||||
|
BlockdevCommand::Ioctl("set readahead", BLKRASET, IoctlCommand::SetAttribute),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"setro",
|
||||||
|
BlockdevCommand::Ioctl("set read-only", BLKROSET, IoctlCommand::Operation(1)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"setrw",
|
||||||
|
BlockdevCommand::Ioctl("set read-write", BLKROSET, IoctlCommand::Operation(0)),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
mod linux {
|
||||||
|
use crate::*;
|
||||||
|
use std::{fs::File, io, os::fd::AsRawFd};
|
||||||
|
use std::{io::Read, os::unix::fs::MetadataExt, path::Path};
|
||||||
|
use uucore::{error::UIoError, libc};
|
||||||
|
|
||||||
|
unsafe fn uu_ioctl<T>(device_file: &File, ioctl_code: u32, input: T) -> UResult<()> {
|
||||||
|
if libc::ioctl(device_file.as_raw_fd(), ioctl_code.into(), input) < 0 {
|
||||||
|
Err(Box::new(UIoError::from(io::Error::last_os_error())))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_ioctl_attribute(
|
||||||
|
device_file: &File,
|
||||||
|
ioctl_code: u32,
|
||||||
|
ioctl_type: IoctlArgType,
|
||||||
|
) -> UResult<u64> {
|
||||||
|
unsafe fn ioctl_get<T: Default + Into<u64>>(
|
||||||
|
device: &File,
|
||||||
|
ioctl_code: u32,
|
||||||
|
) -> UResult<u64> {
|
||||||
|
let mut retval: T = Default::default();
|
||||||
|
uu_ioctl(device, ioctl_code, &mut retval as *mut T as usize).map(|_| retval.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
match ioctl_type {
|
||||||
|
IoctlArgType::Int => ioctl_get::<libc::c_uint>(device_file, ioctl_code),
|
||||||
|
IoctlArgType::Long => ioctl_get::<libc::c_ulong>(device_file, ioctl_code),
|
||||||
|
IoctlArgType::Short => ioctl_get::<libc::c_ushort>(device_file, ioctl_code),
|
||||||
|
IoctlArgType::U64 => ioctl_get::<u64>(device_file, ioctl_code),
|
||||||
|
IoctlArgType::U64Sectors => Ok(ioctl_get::<u64>(device_file, ioctl_code)? / 512),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_partition_offset(device_file: &File) -> UResult<usize> {
|
||||||
|
let rdev = device_file.metadata()?.rdev();
|
||||||
|
let major = unsafe { libc::major(rdev) };
|
||||||
|
let minor = unsafe { libc::minor(rdev) };
|
||||||
|
if Path::new(&format!("/sys/dev/block/{}:{}/partition", major, minor)).exists() {
|
||||||
|
let mut start_fd = File::open(format!("/sys/dev/block/{}:{}/start", major, minor))?;
|
||||||
|
let mut str = String::new();
|
||||||
|
start_fd.read_to_string(&mut str)?;
|
||||||
|
return str
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| USimpleError::new(1, "Unable to parse partition start offset"));
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_report(device_path: &str) -> UResult<()> {
|
||||||
|
let device_file = File::open(device_path)?;
|
||||||
|
let partition_offset = get_partition_offset(&device_file)?;
|
||||||
|
let report_ioctls = &["getro", "getra", "getss", "getbsz", "getsize64"];
|
||||||
|
let ioctl_values = report_ioctls
|
||||||
|
.iter()
|
||||||
|
.map(|flag| {
|
||||||
|
let Some((
|
||||||
|
_,
|
||||||
|
BlockdevCommand::Ioctl(_, ioctl_code, IoctlCommand::GetAttribute(ioctl_type)),
|
||||||
|
)) = BLOCKDEV_ACTIONS.iter().find(|(n, _)| flag == n)
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
unsafe { get_ioctl_attribute(&device_file, *ioctl_code, *ioctl_type) }
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<u64>, _>>()?;
|
||||||
|
println!(
|
||||||
|
"{} {:5} {:5} {:5} {:15} {:15} {}",
|
||||||
|
if ioctl_values[0] == 1 { "ro" } else { "rw" },
|
||||||
|
ioctl_values[1],
|
||||||
|
ioctl_values[2],
|
||||||
|
ioctl_values[3],
|
||||||
|
partition_offset,
|
||||||
|
ioctl_values[4],
|
||||||
|
device_path
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_ioctl_command(
|
||||||
|
device: &File,
|
||||||
|
name: &str,
|
||||||
|
ioctl_code: u32,
|
||||||
|
ioctl_action: &IoctlCommand,
|
||||||
|
verbose: bool,
|
||||||
|
arg: usize,
|
||||||
|
) -> UResult<()> {
|
||||||
|
match ioctl_action {
|
||||||
|
IoctlCommand::GetAttribute(ioctl_type) => {
|
||||||
|
let ret = unsafe { get_ioctl_attribute(device, ioctl_code, *ioctl_type)? };
|
||||||
|
if verbose {
|
||||||
|
println!("{}: {}", name, ret);
|
||||||
|
} else {
|
||||||
|
println!("{}", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IoctlCommand::SetAttribute => {
|
||||||
|
unsafe { uu_ioctl(device, ioctl_code, arg)? };
|
||||||
|
if verbose {
|
||||||
|
println!("{} succeeded.", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IoctlCommand::Operation(param) => {
|
||||||
|
unsafe { uu_ioctl(device, ioctl_code, param)? };
|
||||||
|
if verbose {
|
||||||
|
println!("{} succeeded.", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use linux::*;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[uucore::main]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
|
||||||
|
let devices = matches
|
||||||
|
.get_many::<String>("devices")
|
||||||
|
.expect("Required command-line argument");
|
||||||
|
|
||||||
|
if matches.get_flag("report") {
|
||||||
|
println!("RO RA SSZ BSZ StartSec Size Device");
|
||||||
|
for device_path in devices {
|
||||||
|
uucore::show_if_err!(do_report(device_path));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
// Recover arguments from clap in the same order they were passed
|
||||||
|
// Based on https://docs.rs/clap/latest/clap/_cookbook/find/index.html
|
||||||
|
let mut operations = BTreeMap::new();
|
||||||
|
for (id, op) in BLOCKDEV_ACTIONS {
|
||||||
|
if matches.value_source(id) != Some(clap::parser::ValueSource::CommandLine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let indices = matches.indices_of(id).unwrap();
|
||||||
|
let values = matches.get_many::<usize>(id).unwrap();
|
||||||
|
for (index, value) in indices.zip(values) {
|
||||||
|
operations.insert(index, (op.clone(), *value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for device_path in devices {
|
||||||
|
let mut verbose = false;
|
||||||
|
let device_file = File::open(device_path)?;
|
||||||
|
for (operation, value) in operations.values() {
|
||||||
|
match operation {
|
||||||
|
BlockdevCommand::SetVerbosity(true) => verbose = true,
|
||||||
|
BlockdevCommand::SetVerbosity(false) => verbose = false,
|
||||||
|
BlockdevCommand::Ioctl(description, ioctl_code, ioctl_action) => {
|
||||||
|
if let Err(e) = do_ioctl_command(
|
||||||
|
&device_file,
|
||||||
|
description,
|
||||||
|
*ioctl_code,
|
||||||
|
ioctl_action,
|
||||||
|
verbose,
|
||||||
|
*value,
|
||||||
|
) {
|
||||||
|
if verbose {
|
||||||
|
println!("{} failed.", description);
|
||||||
|
}
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uu_app() -> Command {
|
||||||
|
let mut cmd = Command::new(uucore::util_name())
|
||||||
|
.version(crate_version!())
|
||||||
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
|
.infer_long_args(true)
|
||||||
|
.arg(
|
||||||
|
Arg::new("report")
|
||||||
|
.long("report")
|
||||||
|
.help("print report for specified devices")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
)
|
||||||
|
.arg(Arg::new("devices").required(true).action(ArgAction::Append));
|
||||||
|
|
||||||
|
for (flag, action) in BLOCKDEV_ACTIONS {
|
||||||
|
let mut arg = Arg::new(flag)
|
||||||
|
.long(flag)
|
||||||
|
.conflicts_with("report")
|
||||||
|
.action(ArgAction::Append)
|
||||||
|
.value_parser(value_parser!(usize));
|
||||||
|
|
||||||
|
match action {
|
||||||
|
BlockdevCommand::SetVerbosity(true) => {
|
||||||
|
arg = arg.short('v').help("verbose mode");
|
||||||
|
}
|
||||||
|
BlockdevCommand::SetVerbosity(false) => {
|
||||||
|
arg = arg.short('q').help("quiet mode");
|
||||||
|
}
|
||||||
|
BlockdevCommand::Ioctl(name, _, _) => {
|
||||||
|
arg = arg.help(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match action {
|
||||||
|
BlockdevCommand::Ioctl(_, _, IoctlCommand::SetAttribute) => {
|
||||||
|
arg = arg.num_args(1);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
arg = arg
|
||||||
|
.num_args(0)
|
||||||
|
.default_value("0")
|
||||||
|
.default_missing_value("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd = cmd.arg(arg);
|
||||||
|
}
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
#[uucore::main]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
|
||||||
|
|
||||||
|
Err(uucore::error::USimpleError::new(
|
||||||
|
1,
|
||||||
|
"`blockdev` is available only on Linux.",
|
||||||
|
))
|
||||||
|
}
|
1
src/uu/blockdev/src/main.rs
Normal file
1
src/uu/blockdev/src/main.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
uucore::bin!(uu_blockdev);
|
70
tests/by-util/test_blockdev.rs
Normal file
70
tests/by-util/test_blockdev.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// This file is part of the uutils util-linux package.
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
|
use crate::common::util::TestScenario;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_arg() {
|
||||||
|
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_report_mutually_exclusive_with_others() {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("--report")
|
||||||
|
.arg("--getalignoff")
|
||||||
|
.arg("/foo")
|
||||||
|
.fails()
|
||||||
|
.code_is(1)
|
||||||
|
.stderr_contains("the argument '--report' cannot be used with '--getalignoff'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
mod linux {
|
||||||
|
use crate::common::util::TestScenario;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fails_on_first_error() {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("-v")
|
||||||
|
.arg("--getalignoff")
|
||||||
|
.arg("--getbsz")
|
||||||
|
.arg("/dev/null")
|
||||||
|
.fails()
|
||||||
|
.code_is(1)
|
||||||
|
.stdout_is("get alignment offset in bytes failed.\n")
|
||||||
|
.stderr_contains("Inappropriate ioctl for device");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_report_continues_on_errors() {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("--report")
|
||||||
|
.arg("/dev/null")
|
||||||
|
.arg("/non/existing")
|
||||||
|
.fails()
|
||||||
|
.code_is(1)
|
||||||
|
.stderr_matches(
|
||||||
|
&Regex::new("(?ms)Inappropriate ioctl for device.*No such file or directory")
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
mod non_linux {
|
||||||
|
use crate::common::util::TestScenario;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fails_on_unsupported_platforms() {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("--report")
|
||||||
|
.arg("/dev/null")
|
||||||
|
.fails()
|
||||||
|
.code_is(1)
|
||||||
|
.stderr_is("blockdev: `blockdev` is available only on Linux.\n");
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,10 @@ mod test_lsmem;
|
|||||||
#[path = "by-util/test_mountpoint.rs"]
|
#[path = "by-util/test_mountpoint.rs"]
|
||||||
mod test_mountpoint;
|
mod test_mountpoint;
|
||||||
|
|
||||||
|
#[cfg(feature = "blockdev")]
|
||||||
|
#[path = "by-util/test_blockdev.rs"]
|
||||||
|
mod test_blockdev;
|
||||||
|
|
||||||
#[cfg(feature = "ctrlaltdel")]
|
#[cfg(feature = "ctrlaltdel")]
|
||||||
#[path = "by-util/test_ctrlaltdel.rs"]
|
#[path = "by-util/test_ctrlaltdel.rs"]
|
||||||
mod test_ctrlaltdel;
|
mod test_ctrlaltdel;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user