1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

mkfifo: better handle the mode + umask

Should make tests/misc/mknod.sh pass
This commit is contained in:
Sylvestre Ledru 2024-12-18 20:42:28 +01:00
parent 55ffdb0847
commit 31ffc3a0eb
3 changed files with 63 additions and 5 deletions

View file

@ -19,7 +19,7 @@ path = "src/mkfifo.rs"
[dependencies] [dependencies]
clap = { workspace = true } clap = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
uucore = { workspace = true } uucore = { workspace = true, features = ["fs"] }
[[bin]] [[bin]]
name = "mkfifo" name = "mkfifo"

View file

@ -6,6 +6,8 @@
use clap::{crate_version, Arg, ArgAction, Command}; use clap::{crate_version, Arg, ArgAction, Command};
use libc::mkfifo; use libc::mkfifo;
use std::ffi::CString; use std::ffi::CString;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError}; use uucore::error::{UResult, USimpleError};
use uucore::{format_usage, help_about, help_usage, show}; use uucore::{format_usage, help_about, help_usage, show};
@ -32,11 +34,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
let mode = match matches.get_one::<String>(options::MODE) { let mode = match matches.get_one::<String>(options::MODE) {
// if mode is passed, ignore umask
Some(m) => match usize::from_str_radix(m, 8) { Some(m) => match usize::from_str_radix(m, 8) {
Ok(m) => m, Ok(m) => m,
Err(e) => return Err(USimpleError::new(1, format!("invalid mode: {e}"))), Err(e) => return Err(USimpleError::new(1, format!("invalid mode: {e}"))),
}, },
None => 0o666, // Default value + umask if present
None => 0o666 & !(uucore::mode::get_umask() as usize),
}; };
let fifos: Vec<String> = match matches.get_many::<String>(options::FIFO) { let fifos: Vec<String> = match matches.get_many::<String>(options::FIFO) {
@ -47,12 +51,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
for f in fifos { for f in fifos {
let err = unsafe { let err = unsafe {
let name = CString::new(f.as_bytes()).unwrap(); let name = CString::new(f.as_bytes()).unwrap();
mkfifo(name.as_ptr(), mode as libc::mode_t) mkfifo(name.as_ptr(), 0o666)
}; };
if err == -1 { if err == -1 {
show!(USimpleError::new( show!(USimpleError::new(
1, 1,
format!("cannot create fifo {}: File exists", f.quote()) format!("cannot create fifo {}: File exists", f.quote()),
));
}
// Explicitly set the permissions to ignore umask
if let Err(e) = fs::set_permissions(&f, fs::Permissions::from_mode(mode as u32)) {
return Err(USimpleError::new(
1,
format!("cannot set permissions on {}: {}", f.quote(), e),
)); ));
} }
} }
@ -71,7 +83,6 @@ pub fn uu_app() -> Command {
.short('m') .short('m')
.long(options::MODE) .long(options::MODE)
.help("file permissions for the fifo") .help("file permissions for the fifo")
.default_value("0666")
.value_name("MODE"), .value_name("MODE"),
) )
.arg( .arg(

View file

@ -52,3 +52,50 @@ fn test_create_one_fifo_already_exists() {
.fails() .fails()
.stderr_is("mkfifo: cannot create fifo 'abcdef': File exists\n"); .stderr_is("mkfifo: cannot create fifo 'abcdef': File exists\n");
} }
#[test]
fn test_create_fifo_with_mode_and_umask() {
use uucore::fs::display_permissions;
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let test_fifo_creation = |mode: &str, umask: u16, expected: &str| {
scene
.ucmd()
.arg("-m")
.arg(mode)
.arg(format!("fifo_test_{mode}"))
.umask(libc::mode_t::from(umask))
.succeeds();
let metadata = std::fs::metadata(at.subdir.join(format!("fifo_test_{mode}"))).unwrap();
let permissions = display_permissions(&metadata, true);
assert_eq!(permissions, expected.to_string());
};
test_fifo_creation("734", 0o077, "prwx-wxr--"); // spell-checker:disable-line
test_fifo_creation("706", 0o777, "prwx---rw-"); // spell-checker:disable-line
}
#[test]
fn test_create_fifo_with_umask() {
use uucore::fs::display_permissions;
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let test_fifo_creation = |umask: u16, expected: &str| {
scene
.ucmd()
.arg("fifo_test")
.umask(libc::mode_t::from(umask))
.succeeds();
let metadata = std::fs::metadata(at.subdir.join("fifo_test")).unwrap();
let permissions = display_permissions(&metadata, true);
assert_eq!(permissions, expected.to_string());
at.remove("fifo_test");
};
test_fifo_creation(0o022, "prw-r--r--"); // spell-checker:disable-line
test_fifo_creation(0o777, "p---------"); // spell-checker:disable-line
}