Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
aea644b
sort: add collation key arena storage to LineData
sylvestre Mar 18, 2026
436648e
refactor: replace nix::libc re-exports with direct libc imports
sylvestre Mar 27, 2026
b4ee7f4
refactor: add libc-based signal wrappers in uucore::signals::csignal
sylvestre Mar 27, 2026
0e29161
refactor: migrate pipes.rs and cat splice.rs from nix to rustix
sylvestre Mar 28, 2026
f92965e
refactor: migrate uucore process.rs from nix to rustix
sylvestre Mar 28, 2026
5071765
refactor: migrate safe_traversal.rs from nix to rustix
sylvestre Mar 28, 2026
e76074c
refactor: migrate signals.rs and lib.rs from nix to csignal/rustix
sylvestre Mar 28, 2026
efaf2a6
refactor: migrate all utilities from nix to rustix/libc
sylvestre Mar 28, 2026
6f5a967
refactor: remove nix from uucore and date, complete source migration
sylvestre Mar 28, 2026
04eea4c
refactor(kill): remove unsafe libc::kill, use safe rustix process APIs
sylvestre Mar 28, 2026
4c506fc
refactor(mknod): remove unsafe libc::mknod and libc::umask calls
sylvestre Mar 28, 2026
ba36603
refactor(mkfifo): remove unsafe libc::mkfifo, use safe rustix::fs::mk…
sylvestre Mar 28, 2026
b21968e
refactor(sort): replace unsafe libc::fcntl with rustix::io::fcntl_getfd
sylvestre Mar 28, 2026
3fea029
refactor(sync): remove unsafe libc::open/close, use safe rustix::fs::…
sylvestre Mar 28, 2026
c72649d
spell: more jargon
sylvestre Mar 30, 2026
002415b
fix(env): skip uncatchable signals on OpenBSD when applying to all si…
sylvestre Mar 30, 2026
d449548
deps(rustix): enable use-libc to route syscalls through glibc
sylvestre Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude
26 changes: 26 additions & 0 deletions .vscode/cspell.dictionaries/jargon.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,29 @@ Hijri
Nowruz
charmap
hijri

csignal
noent
nptl
oldset
ptrs
rdband
rustix
setmask
sigaddset
sigemptyset
sigfillset
sighandler
sigmask
signum
sigprocmask
sigrtmin
sigset
sigsys
esrch
SRCH
Nofile
rprocess
statat
getdents
SIGTHR
1 change: 1 addition & 0 deletions CLAUDE.md
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,9 @@ rstest = "0.26.0"
rstest_reuse = "0.7.0"
rustc-hash = "2.1.1"
rust-ini = "0.21.0"
# binary name of coreutils can be hijacked by overriding getauxval via LD_PRELOAD
# So we use param and avoid libc backend
rustix = { version = "1.1.4", features = ["param"] }
# param: binary name of coreutils can be hijacked by overriding getauxval via LD_PRELOAD
# use-libc: route syscalls through glibc (not direct asm) for LD_PRELOAD/sanitizer compat
rustix = { version = "1.1.4", features = ["param", "use-libc"] }
same-file = "1.0.6"
self_cell = "1.0.4"
selinux = "0.6"
Expand Down
1 change: 0 additions & 1 deletion src/uu/cp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ fluent = { workspace = true }

[target.'cfg(unix)'.dependencies]
exacl = { workspace = true, optional = true }
nix = { workspace = true, features = ["fs"] }

[[bin]]
name = "cp"
Expand Down
31 changes: 24 additions & 7 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion src/uu/dd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
61 changes: 31 additions & 30 deletions src/uu/dd/src/dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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"
}
}
}
Expand Down Expand Up @@ -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"
}
}
}
Expand All @@ -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
Expand Down Expand Up @@ -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 _),
)?;
}

Expand Down
4 changes: 2 additions & 2 deletions src/uu/dd/src/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,8 @@ extern "C" fn sigusr1_handler(_: std::os::raw::c_int) {
}

#[cfg(target_os = "linux")]
pub(crate) fn install_sigusr1_handler() -> Result<(), nix::errno::Errno> {
uucore::signals::install_signal_handler(nix::sys::signal::Signal::SIGUSR1, sigusr1_handler)
pub(crate) fn install_sigusr1_handler() -> std::io::Result<()> {
uucore::signals::install_signal_handler(libc::SIGUSR1, sigusr1_handler)
}

/// Return a closure that can be used in its own thread to print progress info.
Expand Down
2 changes: 1 addition & 1 deletion src/uu/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading
Loading