1
Fork 0
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:
Terts Diepraam 2022-09-29 22:31:02 +02:00
parent d509c16a22
commit 1d6c5d14b2
3 changed files with 33 additions and 50 deletions

View file

@ -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"] }

View file

@ -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())
}

View file

@ -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]