mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
refactor(mknod): remove unsafe libc::mknod and libc::umask calls
Replace unsafe libc::mknod() with safe rustix::fs::mknodat(CWD, ...) and unsafe libc::umask() with safe rustix::process::umask().
This commit is contained in:
Generated
+2
-1
@@ -3782,7 +3782,8 @@ version = "0.8.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fluent",
|
||||
"nix",
|
||||
"libc",
|
||||
"rustix",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ doctest = false
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["mode", "fs"] }
|
||||
fluent = { workspace = true }
|
||||
nix = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
rustix = { workspace = true, features = ["fs", "process"] }
|
||||
|
||||
[features]
|
||||
selinux = ["uucore/selinux"]
|
||||
|
||||
+35
-34
@@ -6,8 +6,8 @@
|
||||
// spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO sflag
|
||||
|
||||
use clap::{Arg, ArgAction, Command, value_parser};
|
||||
use nix::libc::{S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, mode_t};
|
||||
use nix::sys::stat::{Mode, SFlag, mknod as nix_mknod, umask as nix_umask};
|
||||
use libc::{S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, mode_t};
|
||||
use rustix::fs::Mode;
|
||||
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{UResult, USimpleError, UUsageError, set_exit_code};
|
||||
@@ -28,28 +28,18 @@ mod options {
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum FileType {
|
||||
enum FileTypeArg {
|
||||
Block,
|
||||
Character,
|
||||
Fifo,
|
||||
}
|
||||
|
||||
impl FileType {
|
||||
fn as_sflag(&self) -> SFlag {
|
||||
match self {
|
||||
Self::Block => SFlag::S_IFBLK,
|
||||
Self::Character => SFlag::S_IFCHR,
|
||||
Self::Fifo => SFlag::S_IFIFO,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for special inode creation.
|
||||
struct Config {
|
||||
/// Permission bits for the inode
|
||||
mode: Mode,
|
||||
|
||||
file_type: FileType,
|
||||
file_type: FileTypeArg,
|
||||
|
||||
/// when false, the exact mode bits will be set
|
||||
use_umask: bool,
|
||||
@@ -72,34 +62,45 @@ struct Config {
|
||||
}
|
||||
|
||||
fn mknod(file_name: &str, config: Config) -> i32 {
|
||||
use rustix::process::umask;
|
||||
|
||||
// set umask to 0 and store previous umask
|
||||
let have_prev_umask = if config.use_umask {
|
||||
None
|
||||
} else {
|
||||
Some(nix_umask(Mode::empty()))
|
||||
Some(umask(Mode::empty()))
|
||||
};
|
||||
|
||||
let mknod_err = nix_mknod(
|
||||
file_name,
|
||||
config.file_type.as_sflag(),
|
||||
config.mode,
|
||||
config.dev as _,
|
||||
)
|
||||
.err();
|
||||
let errno = if mknod_err.is_some() { -1 } else { 0 };
|
||||
let file_type_bits: mode_t = match config.file_type {
|
||||
FileTypeArg::Block => libc::S_IFBLK,
|
||||
FileTypeArg::Character => libc::S_IFCHR,
|
||||
FileTypeArg::Fifo => libc::S_IFIFO,
|
||||
};
|
||||
let c_path = std::ffi::CString::new(file_name).unwrap();
|
||||
// SAFETY: c_path is a valid null-terminated C string
|
||||
let ret = unsafe {
|
||||
libc::mknod(
|
||||
c_path.as_ptr(),
|
||||
file_type_bits | config.mode.bits() as mode_t,
|
||||
config.dev as _,
|
||||
)
|
||||
};
|
||||
|
||||
// set umask back to original value
|
||||
if let Some(prev_umask) = have_prev_umask {
|
||||
nix_umask(prev_umask);
|
||||
umask(prev_umask);
|
||||
}
|
||||
|
||||
if let Some(err) = mknod_err {
|
||||
let errno = if ret != 0 {
|
||||
eprintln!(
|
||||
"{}: {}",
|
||||
uucore::execution_phrase(),
|
||||
std::io::Error::from(err)
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// Apply SELinux context if requested
|
||||
#[cfg(all(feature = "selinux", any(target_os = "android", target_os = "linux")))]
|
||||
@@ -139,7 +140,7 @@ fn mknod(file_name: &str, config: Config) -> i32 {
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
|
||||
|
||||
let file_type = matches.get_one::<FileType>("type").unwrap();
|
||||
let file_type = matches.get_one::<FileTypeArg>("type").unwrap();
|
||||
|
||||
let mut use_umask = true;
|
||||
let mode_permissions = match matches.get_one::<String>("mode") {
|
||||
@@ -172,8 +173,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
matches.get_one::<u32>(options::MAJOR),
|
||||
matches.get_one::<u32>(options::MINOR),
|
||||
) {
|
||||
(FileType::Fifo, None, None) => 0,
|
||||
(FileType::Fifo, _, _) => {
|
||||
(FileTypeArg::Fifo, None, None) => 0,
|
||||
(FileTypeArg::Fifo, _, _) => {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
translate!("mknod-error-fifo-no-major-minor"),
|
||||
@@ -286,16 +287,16 @@ fn parse_mode(str_mode: &str) -> Result<u32, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_type(tpe: &str) -> Result<FileType, String> {
|
||||
fn parse_type(tpe: &str) -> Result<FileTypeArg, String> {
|
||||
// Only check the first character, to allow mnemonic usage like
|
||||
// 'mknod /dev/rst0 character 18 0'.
|
||||
tpe.chars()
|
||||
.next()
|
||||
.ok_or_else(|| translate!("mknod-error-missing-device-type"))
|
||||
.and_then(|first_char| match first_char {
|
||||
'b' => Ok(FileType::Block),
|
||||
'c' | 'u' => Ok(FileType::Character),
|
||||
'p' => Ok(FileType::Fifo),
|
||||
'b' => Ok(FileTypeArg::Block),
|
||||
'c' | 'u' => Ok(FileTypeArg::Character),
|
||||
'p' => Ok(FileTypeArg::Fifo),
|
||||
_ => Err(translate!("mknod-error-invalid-device-type", "type" => tpe.quote())),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user