mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
mknod: update to clap 4
This commit is contained in:
parent
d509c16a22
commit
1d6c5d14b2
3 changed files with 33 additions and 50 deletions
|
@ -16,7 +16,7 @@ name = "uu_mknod"
|
||||||
path = "src/mknod.rs"
|
path = "src/mknod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.2", features = ["wrap_help", "cargo"] }
|
clap = { version = "4.0", features = ["wrap_help", "cargo"] }
|
||||||
libc = "^0.2.135"
|
libc = "^0.2.135"
|
||||||
uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["mode"] }
|
uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["mode"] }
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,10 @@
|
||||||
|
|
||||||
// spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO
|
// spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO
|
||||||
|
|
||||||
use std::ffi::CString;
|
use clap::{crate_version, value_parser, Arg, ArgMatches, Command};
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
|
||||||
use libc::{dev_t, mode_t};
|
use libc::{dev_t, mode_t};
|
||||||
use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};
|
use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError};
|
use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError};
|
||||||
|
@ -51,6 +50,13 @@ fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
|
||||||
panic!("Unsupported for windows platform")
|
panic!("Unsupported for windows platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
enum FileType {
|
||||||
|
Block,
|
||||||
|
Character,
|
||||||
|
Fifo,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
|
fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
|
||||||
let c_str = CString::new(file_name).expect("Failed to convert to CString");
|
let c_str = CString::new(file_name).expect("Failed to convert to CString");
|
||||||
|
@ -94,16 +100,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.get_one::<String>("name")
|
.get_one::<String>("name")
|
||||||
.expect("Missing argument 'NAME'");
|
.expect("Missing argument 'NAME'");
|
||||||
|
|
||||||
// Only check the first character, to allow mnemonic usage like
|
let file_type = matches.get_one::<FileType>("type").unwrap();
|
||||||
// 'mknod /dev/rst0 character 18 0'.
|
|
||||||
let ch = matches
|
|
||||||
.get_one::<String>("type")
|
|
||||||
.expect("Missing argument 'TYPE'")
|
|
||||||
.chars()
|
|
||||||
.next()
|
|
||||||
.expect("Failed to get the first char");
|
|
||||||
|
|
||||||
if ch == 'p' {
|
if *file_type == FileType::Fifo {
|
||||||
if matches.contains_id("major") || matches.contains_id("minor") {
|
if matches.contains_id("major") || matches.contains_id("minor") {
|
||||||
Err(UUsageError::new(
|
Err(UUsageError::new(
|
||||||
1,
|
1,
|
||||||
|
@ -116,28 +115,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match (
|
match (
|
||||||
matches.get_one::<String>("major"),
|
matches.get_one::<u64>("major"),
|
||||||
matches.get_one::<String>("minor"),
|
matches.get_one::<u64>("minor"),
|
||||||
) {
|
) {
|
||||||
(None, None) | (_, None) | (None, _) => {
|
(_, None) | (None, _) => {
|
||||||
return Err(UUsageError::new(
|
return Err(UUsageError::new(
|
||||||
1,
|
1,
|
||||||
"Special files require major and minor device numbers.",
|
"Special files require major and minor device numbers.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Some(major), Some(minor)) => {
|
(Some(&major), Some(&minor)) => {
|
||||||
let major = major.parse::<u64>().expect("validated by clap");
|
|
||||||
let minor = minor.parse::<u64>().expect("validated by clap");
|
|
||||||
|
|
||||||
let dev = makedev(major, minor);
|
let dev = makedev(major, minor);
|
||||||
let exit_code = if ch == 'b' {
|
let exit_code = match file_type {
|
||||||
// block special file
|
FileType::Block => _mknod(file_name, S_IFBLK | mode, dev),
|
||||||
_mknod(file_name, S_IFBLK | mode, dev)
|
FileType::Character => _mknod(file_name, S_IFCHR | mode, dev),
|
||||||
} else if ch == 'c' || ch == 'u' {
|
_ => unreachable!("file_type was validated to be only block or character"),
|
||||||
// char special file
|
|
||||||
_mknod(file_name, S_IFCHR | mode, dev)
|
|
||||||
} else {
|
|
||||||
unreachable!("{} was validated to be only b, c or u", ch);
|
|
||||||
};
|
};
|
||||||
set_exit_code(exit_code);
|
set_exit_code(exit_code);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -146,7 +138,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app<'a>() -> Command<'a> {
|
pub fn uu_app() -> Command {
|
||||||
Command::new(uucore::util_name())
|
Command::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(format_usage(USAGE))
|
.override_usage(format_usage(USAGE))
|
||||||
|
@ -165,7 +157,6 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.value_name("NAME")
|
.value_name("NAME")
|
||||||
.help("name of the new file")
|
.help("name of the new file")
|
||||||
.required(true)
|
.required(true)
|
||||||
.index(1)
|
|
||||||
.value_hint(clap::ValueHint::AnyPath),
|
.value_hint(clap::ValueHint::AnyPath),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -173,22 +164,19 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.value_name("TYPE")
|
.value_name("TYPE")
|
||||||
.help("type of the new file (b, c, u or p)")
|
.help("type of the new file (b, c, u or p)")
|
||||||
.required(true)
|
.required(true)
|
||||||
.validator(valid_type)
|
.value_parser(parse_type),
|
||||||
.index(2),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("major")
|
Arg::new("major")
|
||||||
.value_name("MAJOR")
|
.value_name("MAJOR")
|
||||||
.help("major file type")
|
.help("major file type")
|
||||||
.validator(valid_u64)
|
.value_parser(value_parser!(u64)),
|
||||||
.index(3),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("minor")
|
Arg::new("minor")
|
||||||
.value_name("MINOR")
|
.value_name("MINOR")
|
||||||
.help("minor file type")
|
.help("minor file type")
|
||||||
.validator(valid_u64)
|
.value_parser(value_parser!(u64)),
|
||||||
.index(4),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,21 +195,16 @@ fn get_mode(matches: &ArgMatches) -> Result<mode_t, String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn valid_type(tpe: &str) -> Result<(), String> {
|
fn parse_type(tpe: &str) -> Result<FileType, String> {
|
||||||
// Only check the first character, to allow mnemonic usage like
|
// Only check the first character, to allow mnemonic usage like
|
||||||
// 'mknod /dev/rst0 character 18 0'.
|
// 'mknod /dev/rst0 character 18 0'.
|
||||||
tpe.chars()
|
tpe.chars()
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| "missing device type".to_string())
|
.ok_or_else(|| "missing device type".to_string())
|
||||||
.and_then(|first_char| {
|
.and_then(|first_char| match first_char {
|
||||||
if vec!['b', 'c', 'u', 'p'].contains(&first_char) {
|
'b' => Ok(FileType::Block),
|
||||||
Ok(())
|
'c' | 'u' => Ok(FileType::Character),
|
||||||
} else {
|
'p' => Ok(FileType::Fifo),
|
||||||
Err(format!("invalid device type {}", tpe.quote()))
|
_ => Err(format!("invalid device type {}", tpe.quote())),
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn valid_u64(num: &str) -> Result<(), String> {
|
|
||||||
num.parse::<u64>().map(|_| ()).map_err(|_| num.into())
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn test_mknod_help() {
|
||||||
.arg("--help")
|
.arg("--help")
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.no_stderr()
|
.no_stderr()
|
||||||
.stdout_contains("USAGE:");
|
.stdout_contains("Usage:");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -92,14 +92,14 @@ fn test_mknod_character_device_requires_major_and_minor() {
|
||||||
.arg("1")
|
.arg("1")
|
||||||
.arg("c")
|
.arg("c")
|
||||||
.fails()
|
.fails()
|
||||||
.stderr_contains("Invalid value \"c\" for '<MINOR>'");
|
.stderr_contains("Invalid value \"c\"");
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
.arg("test_file")
|
.arg("test_file")
|
||||||
.arg("c")
|
.arg("c")
|
||||||
.arg("c")
|
.arg("c")
|
||||||
.arg("1")
|
.arg("1")
|
||||||
.fails()
|
.fails()
|
||||||
.stderr_contains("Invalid value \"c\" for '<MAJOR>'");
|
.stderr_contains("Invalid value \"c\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue