refactor: migrate all utilities from nix to rustix/libc

Migrate 19 utility crates from nix to rustix and direct libc calls:

- kill, timeout, env: signal handling via csignal wrappers + libc
- sync, cat, tail, dd, tsort: file operations via rustix::fs
- touch: futimens via rustix::fs::futimens
- stty, tty: terminal ops via rustix::termios + libc ioctl
- sort: getrlimit via rustix::process, sysconf via libc
- wc, cp, df: stat/fstat via rustix::fs
- nice: priority via rustix::process
- mkfifo, mknod: via direct libc calls

Also add rustix::io::Errno conversions to uucore error.rs.
This commit is contained in:
Sylvestre Ledru
2026-03-28 13:03:13 +01:00
parent 01083b3702
commit 2d0e1f3a77
26 changed files with 453 additions and 427 deletions
Generated
+10 -10
View File
@@ -3405,7 +3405,6 @@ dependencies = [
"fluent",
"indicatif",
"libc",
"nix",
"selinux",
"tempfile",
"thiserror 2.0.18",
@@ -3466,7 +3465,7 @@ dependencies = [
"fluent",
"gcd",
"libc",
"nix",
"rustix",
"tempfile",
"thiserror 2.0.18",
"uucore",
@@ -3543,7 +3542,7 @@ version = "0.8.0"
dependencies = [
"clap",
"fluent",
"nix",
"libc",
"rust-ini",
"thiserror 2.0.18",
"uucore",
@@ -3708,7 +3707,7 @@ version = "0.8.0"
dependencies = [
"clap",
"fluent",
"nix",
"libc",
"uucore",
]
@@ -3787,7 +3786,7 @@ version = "0.8.0"
dependencies = [
"clap",
"fluent",
"nix",
"libc",
"uucore",
]
@@ -3797,7 +3796,7 @@ version = "0.8.0"
dependencies = [
"clap",
"fluent",
"nix",
"libc",
"uucore",
]
@@ -4156,9 +4155,9 @@ dependencies = [
"foldhash 0.2.0",
"itertools 0.14.0",
"memchr",
"nix",
"rand 0.10.1",
"rayon",
"rustix",
"self_cell",
"tempfile",
"thiserror 2.0.18",
@@ -4215,7 +4214,8 @@ dependencies = [
"cfg_aliases",
"clap",
"fluent",
"nix",
"libc",
"rustix",
"uucore",
]
@@ -4234,7 +4234,8 @@ version = "0.8.0"
dependencies = [
"clap",
"fluent",
"nix",
"libc",
"rustix",
"uucore",
"windows-sys 0.61.2",
]
@@ -4299,7 +4300,6 @@ dependencies = [
"codspeed-divan-compat",
"fluent",
"libc",
"nix",
"uucore",
]
-1
View File
@@ -41,7 +41,6 @@ fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
exacl = { workspace = true, optional = true }
nix = { workspace = true, features = ["fs"] }
[[bin]]
name = "cp"
+24 -7
View File
@@ -23,7 +23,7 @@ use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser, value_pars
use filetime::FileTime;
use indicatif::{ProgressBar, ProgressStyle};
#[cfg(unix)]
use nix::sys::stat::{Mode, SFlag, dev_t, mknod as nix_mknod, mode_t};
use libc::{dev_t, mode_t};
use thiserror::Error;
use platform::copy_on_write;
@@ -2807,14 +2807,31 @@ fn copy_node(
overwrite.verify(dest, debug)?;
fs::remove_file(dest)?;
}
let sflag = if source_metadata.file_type().is_char_device() {
SFlag::S_IFCHR
let sflag: mode_t = if source_metadata.file_type().is_char_device() {
libc::S_IFCHR
} else {
SFlag::S_IFBLK
libc::S_IFBLK
};
let mode = Mode::from_bits_truncate(source_metadata.mode() as mode_t);
nix_mknod(dest, sflag, mode, source_metadata.rdev() as dev_t)
.map_err(|e| translate!("cp-error-cannot-create-special-file", "path" => dest.quote(), "error" => e.desc()).into())
let mode = (source_metadata.mode() as mode_t) & 0o7777;
use std::io;
let c_path = std::ffi::CString::new(dest.as_os_str().as_encoded_bytes())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contains null byte"))?;
// SAFETY: c_path is a valid null-terminated C string
let ret = unsafe {
libc::mknod(
c_path.as_ptr(),
sflag | mode,
source_metadata.rdev() as dev_t,
)
};
if ret != 0 {
let e = io::Error::last_os_error();
return Err(
translate!("cp-error-cannot-create-special-file", "path" => dest.quote(), "error" => uucore::error::strip_errno(&e))
.into(),
);
}
Ok(())
}
fn copy_link(
+1 -1
View File
@@ -33,7 +33,7 @@ thiserror = { workspace = true }
fluent = { workspace = true }
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
nix = { workspace = true, features = ["fs", "signal"] }
rustix = { workspace = true, features = ["fs"] }
[[bin]]
name = "dd"
+31 -30
View File
@@ -16,15 +16,13 @@ mod progress;
use crate::bufferedoutput::BufferedOutput;
use blocks::conv_block_unblock_helper;
use datastructures::{ConversionMode, IConvFlags, IFlags, OConvFlags, OFlags, options};
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::fcntl::FcntlArg;
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::fcntl::OFlag;
use parseargs::Parser;
use progress::ProgUpdateType;
use progress::{ProgUpdate, ReadStat, StatusLevel, WriteStat, gen_prog_updater};
#[cfg(target_os = "linux")]
use progress::{check_and_reset_sigusr1, install_sigusr1_handler};
#[cfg(any(target_os = "linux", target_os = "android"))]
use rustix::fs::OFlags as RustixOFlags;
use uucore::io::OwnedFileDescriptorOrHandle;
use uucore::translate;
@@ -55,10 +53,7 @@ use std::time::{Duration, Instant};
use clap::{Arg, Command};
use gcd::Gcd;
#[cfg(target_os = "linux")]
use nix::{
errno::Errno,
fcntl::{PosixFadviseAdvice, posix_fadvise},
};
use rustix::fs::{Advice as PosixFadviseAdvice, fadvise};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult};
#[cfg(unix)]
@@ -316,14 +311,16 @@ impl Source {
/// portion of the source is no longer needed. If not possible,
/// then this function returns an error.
#[cfg(target_os = "linux")]
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> nix::Result<()> {
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> io::Result<()> {
#[allow(clippy::match_wildcard_for_single_variants)]
match self {
Self::File(f) => {
let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
posix_fadvise(f.as_fd(), offset, len, advice)
let advice = PosixFadviseAdvice::DontNeed;
let len = std::num::NonZeroU64::new(len as u64);
fadvise(f.as_fd(), offset as u64, len, advice)?;
Ok(())
}
_ => Err(Errno::ESPIPE), // "Illegal seek"
_ => Err(io::Error::from_raw_os_error(libc::ESPIPE)), // "Illegal seek"
}
}
}
@@ -700,13 +697,15 @@ impl Dest {
/// specified portion of the destination is no longer needed. If
/// not possible, then this function returns an error.
#[cfg(target_os = "linux")]
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> nix::Result<()> {
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> io::Result<()> {
match self {
Self::File(f, _) => {
let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
posix_fadvise(f.as_fd(), offset, len, advice)
let advice = PosixFadviseAdvice::DontNeed;
let len = std::num::NonZeroU64::new(len as u64);
fadvise(f.as_fd(), offset as u64, len, advice)?;
Ok(())
}
_ => Err(Errno::ESPIPE), // "Illegal seek"
_ => Err(io::Error::from_raw_os_error(libc::ESPIPE)), // "Illegal seek"
}
}
}
@@ -720,31 +719,33 @@ fn is_sparse(buf: &[u8]) -> bool {
/// This follows GNU dd behavior for partial block writes with O_DIRECT.
#[cfg(any(target_os = "linux", target_os = "android"))]
fn handle_o_direct_write(f: &mut File, buf: &[u8], original_error: io::Error) -> io::Result<usize> {
use nix::fcntl::{FcntlArg, OFlag, fcntl};
use rustix::fs::{OFlags, fcntl_getfl, fcntl_setfl};
// Get current flags using nix
let oflags = match fcntl(&mut *f, FcntlArg::F_GETFL) {
Ok(flags) => OFlag::from_bits_retain(flags),
Err(_) => return Err(original_error),
// Get current flags
let Ok(oflags) = fcntl_getfl(&*f) else {
return Err(original_error);
};
// If O_DIRECT is set, try removing it temporarily
if oflags.contains(OFlag::O_DIRECT) {
let flags_without_direct = oflags - OFlag::O_DIRECT;
if oflags.contains(OFlags::DIRECT) {
let flags_without_direct = oflags & !OFlags::DIRECT;
// Remove O_DIRECT flag using nix
if fcntl(&mut *f, FcntlArg::F_SETFL(flags_without_direct)).is_err() {
// Remove O_DIRECT flag
if fcntl_setfl(&*f, flags_without_direct).is_err() {
return Err(original_error);
}
// Retry the write without O_DIRECT
let write_result = f.write(buf);
// Restore O_DIRECT flag using nix (GNU doesn't restore it, but we'll be safer)
// Restore O_DIRECT flag (GNU doesn't restore it, but we'll be safer)
// Log any restoration errors without failing the operation
if let Err(os_err) = fcntl(&mut *f, FcntlArg::F_SETFL(oflags)) {
if let Err(os_err) = fcntl_setfl(&*f, oflags) {
// Just log the error, don't fail the whole operation
show_error!("Failed to restore O_DIRECT flag: {os_err}");
show_error!(
"Failed to restore O_DIRECT flag: {}",
io::Error::from(os_err)
);
}
write_result
@@ -891,9 +892,9 @@ impl<'a> Output<'a> {
let fx = OwnedFileDescriptorOrHandle::from(io::stdout())?;
#[cfg(any(target_os = "linux", target_os = "android"))]
if let Some(libc_flags) = make_linux_oflags(&settings.oflags) {
nix::fcntl::fcntl(
rustix::fs::fcntl_setfl(
fx.as_raw().as_fd(),
FcntlArg::F_SETFL(OFlag::from_bits_retain(libc_flags)),
RustixOFlags::from_bits_retain(libc_flags as _),
)?;
}
+1 -1
View File
@@ -26,7 +26,7 @@ uucore = { workspace = true, features = ["signals"] }
fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["signal"] }
libc = { workspace = true }
[[bin]]
name = "env"
+44 -38
View File
@@ -17,15 +17,6 @@ use ini::Ini;
use native_int_str::{
Convert, NCvt, NativeIntStr, NativeIntString, NativeStr, from_native_int_representation_owned,
};
#[cfg(unix)]
use nix::libc;
#[cfg(unix)]
use nix::sys::signal::{
SigHandler::{SigDfl, SigIgn},
SigSet, SigmaskHow, Signal, signal, sigprocmask,
};
#[cfg(unix)]
use nix::unistd::execvp;
use std::borrow::Cow;
#[cfg(unix)]
use std::collections::{BTreeMap, BTreeSet};
@@ -38,6 +29,8 @@ use std::io::Write as _;
use std::io::stderr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
#[cfg(unix)]
use uucore::signals::csignal::{self, SigHandler};
use uucore::display::{Quotable, print_all_env_vars};
use uucore::error::{ExitCode, UError, UResult, USimpleError, UUsageError};
@@ -295,16 +288,25 @@ fn build_signal_request(
}
#[cfg(unix)]
fn signal_from_value(sig_value: usize) -> UResult<Signal> {
Signal::try_from(sig_value as i32).map_err(|_| {
USimpleError::new(
fn signal_from_value(sig_value: usize) -> UResult<libc::c_int> {
let sig = sig_value as libc::c_int;
// Validate signal number is in a reasonable range.
// On Linux, reject glibc-reserved signals between standard signals and SIGRTMIN
// (typically 32 and 33, used internally by NPTL).
#[cfg(any(target_os = "linux", target_os = "android"))]
let reserved = sig > libc::SIGSYS && sig < libc::SIGRTMIN();
#[cfg(not(any(target_os = "linux", target_os = "android")))]
let reserved = false;
if sig <= 0 || sig >= 128 || reserved {
return Err(USimpleError::new(
125,
translate!(
"env-error-invalid-signal",
"signal" => sig_value.to_string().quote()
),
)
})
));
}
Ok(sig)
}
fn load_config_file(opts: &mut Options) -> UResult<()> {
@@ -836,11 +838,21 @@ impl EnvAppData {
}
// Execute the program using execvp. this replaces the current
// process. The execvp function takes care of appending a NULL
// argument to the argument list so that we don't have to.
match execvp(&prog_cstring, &argv) {
Err(nix::errno::Errno::ENOENT) => Err(self.make_error_no_such_file_or_dir(&prog)),
Err(nix::errno::Errno::EACCES) => {
// process.
//
// Build a null-terminated array of pointers for execvp.
let mut argv_ptrs: Vec<*const libc::c_char> = argv.iter().map(|a| a.as_ptr()).collect();
argv_ptrs.push(std::ptr::null());
// SAFETY: prog_cstring is a valid null-terminated C string,
// argv_ptrs is a null-terminated array of valid C string pointers.
// execvp only returns on error.
unsafe { libc::execvp(prog_cstring.as_ptr(), argv_ptrs.as_ptr()) };
let err = io::Error::last_os_error();
match err.raw_os_error() {
Some(libc::ENOENT) => Err(self.make_error_no_such_file_or_dir(&prog)),
Some(libc::EACCES) => {
uucore::show_error!(
"{}",
translate!(
@@ -850,7 +862,7 @@ impl EnvAppData {
);
Err(126.into())
}
Err(_) => {
_ => {
uucore::show_error!(
"{}",
translate!(
@@ -860,9 +872,6 @@ impl EnvAppData {
);
Err(126.into())
}
Ok(_) => {
unreachable!("execvp should never return on success")
}
}
}
@@ -1072,7 +1081,7 @@ fn apply_signal_action<F>(
signal_fn: F,
) -> UResult<()>
where
F: Fn(Signal) -> UResult<()>,
F: Fn(libc::c_int) -> UResult<()>,
{
request.for_each_signal(|sig_value, explicit| {
// On some platforms ALL_SIGNALS may contain values that are not valid in libc.
@@ -1096,41 +1105,38 @@ where
}
#[cfg(unix)]
fn ignore_signal(sig: Signal) -> UResult<()> {
// SAFETY: This is safe because we write the handler for each signal only once, and therefore "the current handler is the default", as the documentation requires it.
let result = unsafe { signal(sig, SigIgn) };
if let Err(err) = result {
fn ignore_signal(sig: libc::c_int) -> UResult<()> {
if let Err(err) = unsafe { csignal::set_signal_handler(sig, SigHandler::SigIgn) } {
return Err(USimpleError::new(
125,
translate!("env-error-failed-set-signal-action", "signal" => (sig as i32), "error" => err.desc()),
translate!("env-error-failed-set-signal-action", "signal" => sig, "error" => err),
));
}
Ok(())
}
#[cfg(unix)]
fn reset_signal(sig: Signal) -> UResult<()> {
let result = unsafe { signal(sig, SigDfl) };
if let Err(err) = result {
fn reset_signal(sig: libc::c_int) -> UResult<()> {
if let Err(err) = unsafe { csignal::set_signal_handler(sig, SigHandler::SigDfl) } {
return Err(USimpleError::new(
125,
translate!("env-error-failed-set-signal-action", "signal" => (sig as i32), "error" => err.desc()),
translate!("env-error-failed-set-signal-action", "signal" => sig, "error" => err),
));
}
Ok(())
}
#[cfg(unix)]
fn block_signal(sig: Signal) -> UResult<()> {
let mut set = SigSet::empty();
fn block_signal(sig: libc::c_int) -> UResult<()> {
let mut set = csignal::SigSet::empty();
set.add(sig);
if let Err(err) = sigprocmask(SigmaskHow::SIG_BLOCK, Some(&set), None) {
if let Err(err) = csignal::sigprocmask(csignal::SigmaskHow::Block, Some(&set), None) {
return Err(USimpleError::new(
125,
translate!(
"env-error-failed-set-signal-action",
"signal" => (sig as i32),
"error" => err.desc()
"signal" => sig,
"error" => err
),
));
}
+1 -1
View File
@@ -25,7 +25,7 @@ uucore = { workspace = true, features = ["signals"] }
fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["signal"] }
libc = { workspace = true }
[[bin]]
name = "kill"
+10 -14
View File
@@ -6,8 +6,6 @@
// spell-checker:ignore (ToDO) signalname pids killpg
use clap::{Arg, ArgAction, Command};
use nix::sys::signal::{self, Signal};
use nix::unistd::Pid;
use std::io::Error;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};
@@ -69,22 +67,18 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
};
let sig_name = signal_name_by_value(sig);
// Signal does not support converting from EXIT
// Instead, nix::signal::kill expects Option::None to properly handle EXIT
let sig: Option<Signal> = if sig_name.is_some_and(|name| name == "EXIT") {
None
// Signal 0 (EXIT) means "check if process exists" - pass 0 to kill()
let sig_num: i32 = if sig_name.is_some_and(|name| name == "EXIT") {
0
} else {
let sig = (sig as i32)
.try_into()
.map_err(|e| Error::from_raw_os_error(e as i32))?;
Some(sig)
sig as i32
};
let pids = parse_pids(&pids_or_signals)?;
if pids.is_empty() {
Err(USimpleError::new(1, translate!("kill-error-no-process-id")))
} else {
kill(sig, &pids);
kill(sig_num, &pids);
Ok(())
}
}
@@ -250,11 +244,13 @@ fn parse_pids(pids: &[String]) -> UResult<Vec<i32>> {
.collect()
}
fn kill(sig: Option<Signal>, pids: &[i32]) {
fn kill(sig: i32, pids: &[i32]) {
for &pid in pids {
if let Err(e) = signal::kill(Pid::from_raw(pid), sig) {
// SAFETY: kill() is a standard POSIX function. sig=0 checks process existence.
let ret = unsafe { libc::kill(pid, sig) };
if ret != 0 {
show!(
Error::from_raw_os_error(e as i32)
Error::last_os_error()
.map_err_context(|| { translate!("kill-error-sending-signal", "pid" => pid) })
);
}
+1 -1
View File
@@ -25,7 +25,7 @@ uucore = { workspace = true, features = ["fs", "mode"] }
fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["fs"] }
libc = { workspace = true }
[features]
selinux = ["uucore/selinux"]
+4 -3
View File
@@ -4,8 +4,7 @@
// file that was distributed with this source code.
use clap::{Arg, ArgAction, Command, value_parser};
use nix::sys::stat::Mode;
use nix::unistd::mkfifo;
use std::ffi::CString;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use uucore::display::Quotable;
@@ -48,7 +47,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
};
for f in fifos {
if mkfifo(f.as_str(), Mode::from_bits_truncate(0o666)).is_err() {
let c_path = CString::new(f.as_str()).unwrap();
// SAFETY: c_path is a valid null-terminated C string
if unsafe { libc::mkfifo(c_path.as_ptr(), 0o666) } != 0 {
show!(USimpleError::new(
1,
translate!("mkfifo-error-cannot-create-fifo", "path" => f.quote()),
+1 -1
View File
@@ -24,7 +24,7 @@ doctest = false
clap = { workspace = true }
uucore = { workspace = true, features = ["mode", "fs"] }
fluent = { workspace = true }
nix = { workspace = true }
libc = { workspace = true }
[features]
selinux = ["uucore/selinux"]
+19 -20
View File
@@ -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 std::ffi::CString;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError, UUsageError, set_exit_code};
@@ -35,11 +35,11 @@ enum FileType {
}
impl FileType {
fn as_sflag(&self) -> SFlag {
fn as_mode(&self) -> mode_t {
match self {
Self::Block => SFlag::S_IFBLK,
Self::Character => SFlag::S_IFCHR,
Self::Fifo => SFlag::S_IFIFO,
Self::Block => libc::S_IFBLK,
Self::Character => libc::S_IFCHR,
Self::Fifo => libc::S_IFIFO,
}
}
}
@@ -47,7 +47,7 @@ impl FileType {
/// Configuration for special inode creation.
struct Config {
/// Permission bits for the inode
mode: Mode,
mode: mode_t,
file_type: FileType,
@@ -70,28 +70,27 @@ fn mknod(file_name: &str, config: Config) -> i32 {
let have_prev_umask = if config.use_umask {
None
} else {
Some(nix_umask(Mode::empty()))
// SAFETY: umask is a standard POSIX function, always safe to call
Some(unsafe { libc::umask(0) })
};
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 c_path = CString::new(file_name).unwrap();
let combined_mode = config.file_type.as_mode() | config.mode;
// SAFETY: c_path is a valid null-terminated C string
let ret = unsafe { libc::mknod(c_path.as_ptr(), combined_mode, config.dev as _) };
let errno = if ret != 0 { -1 } else { 0 };
// set umask back to original value
if let Some(prev_umask) = have_prev_umask {
nix_umask(prev_umask);
// SAFETY: umask is always safe to call
unsafe { libc::umask(prev_umask) };
}
if let Some(err) = mknod_err {
if ret != 0 {
eprintln!(
"{}: {}",
uucore::execution_phrase(),
std::io::Error::from(err)
std::io::Error::last_os_error()
);
}
@@ -141,7 +140,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
parse_mode(str_mode).map_err(|e| USimpleError::new(1, e))?
}
};
let mode = Mode::from_bits_truncate(mode_permissions as mode_t);
let mode = (mode_permissions as mode_t) & 0o7777;
let file_name = matches
.get_one::<String>("name")
+2 -1
View File
@@ -51,7 +51,8 @@ foldhash = { workspace = true }
ctrlc = { workspace = true }
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["resource"] }
libc = { workspace = true }
rustix = { workspace = true, features = ["process", "param"] }
[dev-dependencies]
divan = { workspace = true }
+7 -10
View File
@@ -110,17 +110,14 @@ fn physical_memory_bytes() -> Option<u128> {
any(target_os = "linux", target_os = "android")
))]
fn physical_memory_bytes_unix() -> Option<u128> {
use nix::unistd::{SysconfVar, sysconf};
let page_size = u128::try_from(rustix::param::page_size()).ok()?;
let pages = match sysconf(SysconfVar::_PHYS_PAGES) {
Ok(Some(pages)) if pages > 0 => u128::try_from(pages).ok()?,
_ => return None,
};
let page_size = match sysconf(SysconfVar::PAGE_SIZE) {
Ok(Some(page_size)) if page_size > 0 => u128::try_from(page_size).ok()?,
_ => return None,
};
// Use libc::sysconf for _SC_PHYS_PAGES since rustix doesn't expose it
let pages = unsafe { libc::sysconf(libc::_SC_PHYS_PAGES) };
if pages <= 0 {
return None;
}
let pages = u128::try_from(pages).ok()?;
Some(pages.saturating_mul(page_size))
}
+6 -5
View File
@@ -1371,14 +1371,15 @@ fn make_sort_mode_arg(mode: &'static str, short: char, help: String) -> Arg {
))
))]
fn get_rlimit() -> UResult<usize> {
use nix::sys::resource::{RLIM_INFINITY, Resource, getrlimit};
use rustix::process::{Resource, getrlimit};
let (rlim_cur, _rlim_max) = getrlimit(Resource::RLIMIT_NOFILE)
.map_err(|_| UUsageError::new(2, translate!("sort-failed-fetch-rlimit")))?;
if rlim_cur == RLIM_INFINITY {
let rlimit = getrlimit(Resource::Nofile);
let rlim_cur = rlimit.current;
if rlim_cur.is_none() {
// None means RLIM_INFINITY
return Err(UUsageError::new(2, translate!("sort-failed-fetch-rlimit")));
}
usize::try_from(rlim_cur)
usize::try_from(rlim_cur.unwrap())
.map_err(|_| UUsageError::new(2, translate!("sort-failed-fetch-rlimit")))
}
+2 -1
View File
@@ -24,7 +24,8 @@ uucore = { workspace = true, features = ["parser"] }
fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["ioctl", "term"] }
libc = { workspace = true }
rustix = { workspace = true, features = ["termios"] }
[[bin]]
name = "stty"
+85 -127
View File
@@ -13,11 +13,8 @@
use crate::Flag;
#[cfg(not(bsd))]
use nix::sys::termios::BaudRate;
use nix::sys::termios::{
ControlFlags as C, InputFlags as I, LocalFlags as L, OutputFlags as O,
SpecialCharacterIndices as S,
use rustix::termios::{
ControlModes as C, InputModes as I, LocalModes as L, OutputModes as O, SpecialCodeIndex as S,
};
#[derive(Debug)]
@@ -31,10 +28,7 @@ pub enum BaudType {
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub enum AllFlags<'a> {
#[cfg(bsd)]
Baud(u32, BaudType),
#[cfg(not(bsd))]
Baud(BaudRate, BaudType),
ControlFlags((&'a Flag<C>, bool)),
InputFlags((&'a Flag<I>, bool)),
LocalFlags((&'a Flag<L>, bool)),
@@ -94,123 +88,88 @@ pub const OUTPUT_FLAGS: &[Flag<O>] = &[
Flag::new("onlcr", O::ONLCR).sane(),
Flag::new("onocr", O::ONOCR),
Flag::new("onlret", O::ONLRET),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
))]
// Output delay flags: only available on Linux (glibc) and Android.
// Not available on BSDs (macOS/iOS), musl, or other platforms in rustix.
#[cfg(any(target_os = "android", target_os = "haiku", target_os = "linux"))]
Flag::new("ofdel", O::OFDEL),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("nl0", O::NL0, O::NLDLY).sane(),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("nl1", O::NL1, O::NLDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("cr0", O::CR0, O::CRDLY).sane(),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("cr1", O::CR1, O::CRDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("cr2", O::CR2, O::CRDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("cr3", O::CR3, O::CRDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("tab0", O::TAB0, O::TABDLY).sane(),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("tab1", O::TAB1, O::TABDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("tab2", O::TAB2, O::TABDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("tab3", O::TAB3, O::TABDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("bs0", O::BS0, O::BSDLY).sane(),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("bs1", O::BS1, O::BSDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("vt0", O::VT0, O::VTDLY).sane(),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("vt1", O::VT1, O::VTDLY),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("ff0", O::FF0, O::FFDLY).sane(),
#[cfg(any(
target_os = "android",
target_os = "haiku",
target_os = "linux",
target_vendor = "apple"
#[cfg(all(
any(target_os = "android", target_os = "haiku", target_os = "linux"),
not(target_env = "musl")
))]
Flag::new_grouped("ff1", O::FF1, O::FFDLY),
];
@@ -241,63 +200,62 @@ pub const LOCAL_FLAGS: &[Flag<L>] = &[
Flag::new("extproc", L::EXTPROC),
];
// BSD's use u32 as baud rate, so using the enum is unnecessary.
// Baud rate table mapping string names to speed values.
// rustix uses actual integer speed values, not encoded B* constants.
#[cfg(not(bsd))]
pub const BAUD_RATES: &[(&str, BaudRate)] = &[
("0", BaudRate::B0),
("50", BaudRate::B50),
("75", BaudRate::B75),
("110", BaudRate::B110),
("134", BaudRate::B134),
("150", BaudRate::B150),
("200", BaudRate::B200),
("300", BaudRate::B300),
("600", BaudRate::B600),
("1200", BaudRate::B1200),
("1800", BaudRate::B1800),
("2400", BaudRate::B2400),
("4800", BaudRate::B4800),
("9600", BaudRate::B9600),
("19200", BaudRate::B19200),
("38400", BaudRate::B38400),
("57600", BaudRate::B57600),
("115200", BaudRate::B115200),
("230400", BaudRate::B230400),
("460800", BaudRate::B460800),
pub const BAUD_RATES: &[(&str, u32)] = &[
("0", 0),
("50", 50),
("75", 75),
("110", 110),
("134", 134),
("150", 150),
("200", 200),
("300", 300),
("600", 600),
("1200", 1200),
("1800", 1800),
("2400", 2400),
("9600", 9600),
("19200", 19200),
("38400", 38400),
("57600", 57600),
("115200", 115_200),
("230400", 230_400),
#[cfg(any(target_os = "android", target_os = "linux"))]
("500000", BaudRate::B500000),
("500000", 500_000),
#[cfg(any(target_os = "android", target_os = "linux"))]
("576000", BaudRate::B576000),
("576000", 576_000),
#[cfg(any(target_os = "android", target_os = "linux"))]
("921600", BaudRate::B921600),
("921600", 921_600),
#[cfg(any(target_os = "android", target_os = "linux"))]
("1000000", BaudRate::B1000000),
("1000000", 1_000_000),
#[cfg(any(target_os = "android", target_os = "linux"))]
("1152000", BaudRate::B1152000),
("1152000", 1_152_000),
#[cfg(any(target_os = "android", target_os = "linux"))]
("1500000", BaudRate::B1500000),
("1500000", 1_500_000),
#[cfg(any(target_os = "android", target_os = "linux"))]
("2000000", BaudRate::B2000000),
("2000000", 2_000_000),
#[cfg(any(
target_os = "android",
all(target_os = "linux", not(target_arch = "sparc64"))
))]
("2500000", BaudRate::B2500000),
("2500000", 2_500_000),
#[cfg(any(
target_os = "android",
all(target_os = "linux", not(target_arch = "sparc64"))
))]
("3000000", BaudRate::B3000000),
("3000000", 3_000_000),
#[cfg(any(
target_os = "android",
all(target_os = "linux", not(target_arch = "sparc64"))
))]
("3500000", BaudRate::B3500000),
("3500000", 3_500_000),
#[cfg(any(
target_os = "android",
all(target_os = "linux", not(target_arch = "sparc64"))
))]
("4000000", BaudRate::B4000000),
("4000000", 4_000_000),
];
/// Control characters for the stty command.
///
+86 -80
View File
@@ -28,11 +28,11 @@ use nix::libc::{O_NONBLOCK, TIOCGWINSZ, TIOCSWINSZ, c_ushort};
))]
use nix::libc::{TCGETS2, termios2};
use nix::sys::termios::{
ControlFlags, InputFlags, LocalFlags, OutputFlags, SetArg, SpecialCharacterIndices as S,
Termios, cfsetispeed, cfsetospeed, tcgetattr, tcsetattr,
use rustix::termios::{
ControlModes as ControlFlags, InputModes as InputFlags, LocalModes as LocalFlags,
OptionalActions, OutputModes as OutputFlags, SpecialCodeIndex as S, Termios, tcgetattr,
tcsetattr,
};
use nix::{ioctl_read_bad, ioctl_write_ptr_bad};
use std::cmp::Ordering;
use std::fs::File;
use std::io::{self, Stdin, stdin, stdout};
@@ -231,19 +231,27 @@ pub struct TermSize {
y: c_ushort,
}
ioctl_read_bad!(
/// Get terminal window size
tiocgwinsz,
TIOCGWINSZ,
TermSize
);
/// Get terminal window size via ioctl
///
/// # Safety
/// `size` must point to a valid, writable `TermSize` and `fd` must be a valid terminal fd.
unsafe fn tiocgwinsz(fd: RawFd, size: *mut TermSize) -> io::Result<()> {
if unsafe { libc::ioctl(fd, TIOCGWINSZ, size) } == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
}
ioctl_write_ptr_bad!(
/// Set terminal window size
tiocswinsz,
TIOCSWINSZ,
TermSize
);
/// Set terminal window size via ioctl
///
/// # Safety
/// `size` must point to a valid `TermSize` and `fd` must be a valid terminal fd.
unsafe fn tiocswinsz(fd: RawFd, size: *mut TermSize) -> io::Result<()> {
if unsafe { libc::ioctl(fd, TIOCSWINSZ, size) } == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
@@ -269,7 +277,7 @@ fn stty(opts: &Options) -> UResult<()> {
));
}
let mut set_arg = SetArg::TCSADRAIN;
let mut set_arg = OptionalActions::Drain;
let mut valid_args: Vec<ArgOptions> = Vec::new();
if let Some(args) = &opts.settings {
@@ -352,10 +360,10 @@ fn stty(opts: &Options) -> UResult<()> {
}
}
"drain" => {
set_arg = SetArg::TCSADRAIN;
set_arg = OptionalActions::Drain;
}
"-drain" => {
set_arg = SetArg::TCSANOW;
set_arg = OptionalActions::Now;
}
"size" => {
valid_args.push(ArgOptions::Print(PrintSetting::Size));
@@ -550,7 +558,7 @@ fn check_flag_group<T>(flag: &Flag<T>, remove: bool) -> bool {
remove && flag.group.is_some()
}
fn print_special_setting(setting: &PrintSetting, fd: i32) -> nix::Result<()> {
fn print_special_setting(setting: &PrintSetting, fd: i32) -> io::Result<()> {
match setting {
PrintSetting::Size => {
let mut size = TermSize::default();
@@ -626,23 +634,23 @@ fn print_terminal_size(
opts: &Options,
window_size: Option<&TermSize>,
term_size: Option<&TermSize>,
) -> nix::Result<()> {
) -> io::Result<()> {
// GNU linked against glibc 2.42 provides us baudrate 51 which panics cfgetospeed
#[cfg(not(target_os = "linux"))]
let speed = nix::sys::termios::cfgetospeed(termios);
#[cfg(target_os = "linux")]
#[cfg(all(not(target_arch = "powerpc"), not(target_arch = "powerpc64")))]
ioctl_read_bad!(tcgets2, TCGETS2, termios2);
let speed = termios.output_speed();
#[cfg(target_os = "linux")]
#[cfg(all(not(target_arch = "powerpc"), not(target_arch = "powerpc64")))]
let speed = {
let mut t2 = unsafe { std::mem::zeroed::<termios2>() };
unsafe { tcgets2(opts.file.as_raw_fd(), &raw mut t2)? };
// SAFETY: TCGETS2 ioctl reads termios2 struct from fd
if unsafe { libc::ioctl(opts.file.as_raw_fd(), TCGETS2, &raw mut t2) } == -1 {
return Err(io::Error::last_os_error());
}
t2.c_ospeed
};
#[cfg(target_os = "linux")]
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
let speed = nix::sys::termios::cfgetospeed(termios);
let speed = termios.output_speed();
let mut printer = WrappedPrinter::new(window_size);
@@ -690,10 +698,7 @@ fn print_terminal_size(
#[cfg(any(target_os = "linux", target_os = "redox"))]
{
// For some reason the normal nix Termios struct does not expose the line,
// so we get the underlying libc::termios struct to get that information.
let libc_termios: nix::libc::termios = termios.clone().into();
let line = libc_termios.c_line;
let line = termios.line_discipline;
printer.print(&translate!("stty-output-line", "line" => line));
}
printer.flush();
@@ -824,7 +829,7 @@ fn string_to_flag(option: &str) -> Option<AllFlags<'_>> {
None
}
fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
fn control_char_to_string(cc: libc::cc_t) -> io::Result<String> {
if cc == 0 {
return Ok(translate!("stty-output-undef"));
}
@@ -844,7 +849,7 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
// DEL character
0x7f => Ok(("^", '?')),
// Out of range (above 8 bits)
_ => Err(nix::errno::Errno::ERANGE),
_ => Err(io::Error::from_raw_os_error(libc::ERANGE)),
}?;
Ok(format!("{meta_prefix}{ctrl_prefix}{character}"))
@@ -854,12 +859,12 @@ fn print_control_chars(
termios: &Termios,
opts: &Options,
term_size: Option<&TermSize>,
) -> nix::Result<()> {
) -> io::Result<()> {
if !opts.all {
// Print only control chars that differ from sane defaults
let mut printer = WrappedPrinter::new(term_size);
for (text, cc_index) in CONTROL_CHARS {
let current_val = termios.control_chars[*cc_index as usize];
let current_val = termios.special_codes[*cc_index];
let sane_val = get_sane_control_char(*cc_index);
if current_val != sane_val {
@@ -877,12 +882,12 @@ fn print_control_chars(
for (text, cc_index) in CONTROL_CHARS {
printer.print(&format!(
"{text} = {};",
control_char_to_string(termios.control_chars[*cc_index as usize])?
control_char_to_string(termios.special_codes[*cc_index])?
));
}
printer.print(&translate!("stty-output-min-time",
"min" => termios.control_chars[S::VMIN as usize],
"time" => termios.control_chars[S::VTIME as usize]
"min" => termios.special_codes[S::VMIN],
"time" => termios.special_codes[S::VTIME]
));
printer.flush();
Ok(())
@@ -891,12 +896,17 @@ fn print_control_chars(
fn print_in_save_format(termios: &Termios) {
print!(
"{:x}:{:x}:{:x}:{:x}",
termios.input_flags.bits(),
termios.output_flags.bits(),
termios.control_flags.bits(),
termios.local_flags.bits()
termios.input_modes.bits(),
termios.output_modes.bits(),
termios.control_modes.bits(),
termios.local_modes.bits()
);
for cc in termios.control_chars {
// Print all special codes in save format by accessing the raw cc array
// via a pointer cast, since rustix doesn't expose the inner array.
let cc_ptr = (&raw const termios.special_codes).cast::<[libc::cc_t; libc::NCCS]>();
// SAFETY: SpecialCodes is a transparent wrapper around [cc_t; NCCS]
let cc_array = unsafe { &*cc_ptr };
for cc in cc_array {
print!(":{cc:x}");
}
println!();
@@ -904,12 +914,12 @@ fn print_in_save_format(termios: &Termios) {
/// Gets terminal size using the tiocgwinsz ioctl system call.
/// This queries the kernel for the current terminal window dimensions.
fn get_terminal_size(fd: RawFd) -> nix::Result<TermSize> {
fn get_terminal_size(fd: RawFd) -> io::Result<TermSize> {
let mut term_size = TermSize::default();
unsafe { tiocgwinsz(fd, &raw mut term_size) }.map(|_| term_size)
}
fn print_settings(termios: &Termios, opts: &Options) -> nix::Result<()> {
fn print_settings(termios: &Termios, opts: &Options) -> io::Result<()> {
if opts.save {
print_in_save_format(termios);
} else {
@@ -972,7 +982,7 @@ fn print_flags<T: TermiosFlag>(
}
/// Apply a single setting
fn apply_setting(termios: &mut Termios, setting: &AllFlags) -> nix::Result<()> {
fn apply_setting(termios: &mut Termios, setting: &AllFlags) -> io::Result<()> {
match setting {
AllFlags::Baud(_, _) => apply_baud_rate_flag(termios, setting)?,
AllFlags::ControlFlags((setting, disable)) => {
@@ -991,14 +1001,14 @@ fn apply_setting(termios: &mut Termios, setting: &AllFlags) -> nix::Result<()> {
Ok(())
}
fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) -> nix::Result<()> {
fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) -> io::Result<()> {
if let AllFlags::Baud(rate, baud_type) = input {
match baud_type {
flags::BaudType::Input => cfsetispeed(termios, *rate)?,
flags::BaudType::Output => cfsetospeed(termios, *rate)?,
flags::BaudType::Input => termios.set_input_speed(*rate)?,
flags::BaudType::Output => termios.set_output_speed(*rate)?,
flags::BaudType::Both => {
cfsetispeed(termios, *rate)?;
cfsetospeed(termios, *rate)?;
termios.set_input_speed(*rate)?;
termios.set_output_speed(*rate)?;
}
}
}
@@ -1006,7 +1016,7 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) -> nix::Result<
}
fn apply_char_mapping(termios: &mut Termios, mapping: &(S, u8)) {
termios.control_chars[mapping.0 as usize] = mapping.1;
termios.special_codes[mapping.0] = mapping.1;
}
/// Apply a saved terminal state to the current termios.
@@ -1027,15 +1037,19 @@ fn apply_saved_state(termios: &mut Termios, state: &[u32]) {
}
// Apply the four flag groups, done (as _) for MacOS size compatibility
termios.input_flags = InputFlags::from_bits_truncate(state[0] as _);
termios.output_flags = OutputFlags::from_bits_truncate(state[1] as _);
termios.control_flags = ControlFlags::from_bits_truncate(state[2] as _);
termios.local_flags = LocalFlags::from_bits_truncate(state[3] as _);
termios.input_modes = InputFlags::from_bits_truncate(state[0] as _);
termios.output_modes = OutputFlags::from_bits_truncate(state[1] as _);
termios.control_modes = ControlFlags::from_bits_truncate(state[2] as _);
termios.local_modes = LocalFlags::from_bits_truncate(state[3] as _);
// Apply control characters if present (stored as u32 but used as u8)
// Access the raw cc array via pointer cast since rustix doesn't expose the inner array.
let cc_ptr = (&raw mut termios.special_codes).cast::<[libc::cc_t; libc::NCCS]>();
// SAFETY: SpecialCodes is a transparent wrapper around [cc_t; NCCS]
let cc_array = unsafe { &mut *cc_ptr };
for (i, &cc_val) in state.iter().skip(4).enumerate() {
if i < termios.control_chars.len() {
termios.control_chars[i] = cc_val as u8;
if i < cc_array.len() {
cc_array[i] = cc_val as u8;
}
}
}
@@ -1044,7 +1058,7 @@ fn apply_special_setting(
_termios: &mut Termios,
setting: &SpecialSetting,
fd: i32,
) -> nix::Result<()> {
) -> io::Result<()> {
let mut size = TermSize::default();
unsafe { tiocgwinsz(fd, &raw mut size)? };
match setting {
@@ -1241,15 +1255,7 @@ fn get_sane_control_char(cc_index: S) -> u8 {
}
}
// Default values for control chars not in the sane list
match cc_index {
S::VEOL => 0,
S::VEOL2 => 0,
S::VMIN => 1,
S::VTIME => 0,
#[cfg(target_os = "linux")]
S::VSWTC => 0,
_ => 0,
}
u8::from(cc_index == S::VMIN)
}
pub fn uu_app() -> Command {
@@ -1291,45 +1297,45 @@ pub fn uu_app() -> Command {
impl TermiosFlag for ControlFlags {
fn is_in(&self, termios: &Termios, group: Option<Self>) -> bool {
termios.control_flags.contains(*self)
&& group.is_none_or(|g| !termios.control_flags.intersects(g - *self))
termios.control_modes.contains(*self)
&& group.is_none_or(|g| !termios.control_modes.intersects(g - *self))
}
fn apply(&self, termios: &mut Termios, val: bool) {
termios.control_flags.set(*self, val);
termios.control_modes.set(*self, val);
}
}
impl TermiosFlag for InputFlags {
fn is_in(&self, termios: &Termios, group: Option<Self>) -> bool {
termios.input_flags.contains(*self)
&& group.is_none_or(|g| !termios.input_flags.intersects(g - *self))
termios.input_modes.contains(*self)
&& group.is_none_or(|g| !termios.input_modes.intersects(g - *self))
}
fn apply(&self, termios: &mut Termios, val: bool) {
termios.input_flags.set(*self, val);
termios.input_modes.set(*self, val);
}
}
impl TermiosFlag for OutputFlags {
fn is_in(&self, termios: &Termios, group: Option<Self>) -> bool {
termios.output_flags.contains(*self)
&& group.is_none_or(|g| !termios.output_flags.intersects(g - *self))
termios.output_modes.contains(*self)
&& group.is_none_or(|g| !termios.output_modes.intersects(g - *self))
}
fn apply(&self, termios: &mut Termios, val: bool) {
termios.output_flags.set(*self, val);
termios.output_modes.set(*self, val);
}
}
impl TermiosFlag for LocalFlags {
fn is_in(&self, termios: &Termios, group: Option<Self>) -> bool {
termios.local_flags.contains(*self)
&& group.is_none_or(|g| !termios.local_flags.intersects(g - *self))
termios.local_modes.contains(*self)
&& group.is_none_or(|g| !termios.local_modes.intersects(g - *self))
}
fn apply(&self, termios: &mut Termios, val: bool) {
termios.local_flags.set(*self, val);
termios.local_modes.set(*self, val);
}
}
+2 -1
View File
@@ -25,7 +25,8 @@ uucore = { workspace = true, features = ["wide"] }
fluent = { workspace = true }
[target.'cfg(unix)'.dependencies]
nix = { workspace = true }
libc = { workspace = true }
rustix = { workspace = true, features = ["fs"] }
[target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { workspace = true, features = [

Some files were not shown because too many files have changed in this diff Show More