diff --git a/Cargo.lock b/Cargo.lock index ddc96adf0..205bfd976 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3782,7 +3782,8 @@ version = "0.8.0" dependencies = [ "clap", "fluent", - "nix", + "libc", + "rustix", "uucore", ] diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index 03ad05b9d..2883fdb20 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -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"] diff --git a/src/uu/mknod/src/mknod.rs b/src/uu/mknod/src/mknod.rs index 9640806d8..16c570ca6 100644 --- a/src/uu/mknod/src/mknod.rs +++ b/src/uu/mknod/src/mknod.rs @@ -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::("type").unwrap(); + let file_type = matches.get_one::("type").unwrap(); let mut use_umask = true; let mode_permissions = match matches.get_one::("mode") { @@ -172,8 +173,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { matches.get_one::(options::MAJOR), matches.get_one::(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 { }) } -fn parse_type(tpe: &str) -> Result { +fn parse_type(tpe: &str) -> Result { // 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())), }) }