From 2e8b6fabcc87de73856530dd49bb2b9876d7c2bc Mon Sep 17 00:00:00 2001 From: Etienne Cordonnier Date: Thu, 22 May 2025 21:53:50 +0200 Subject: [PATCH 1/2] stdbuf: add test_libstdbuf_preload This test verifies that libstdbuf correctly gets preloaded, and that there are no architecture mismatch errors. At the moment the test passes when compiled normally, but fails when compiled with cross-rs, due to https://github.com/uutils/coreutils/issues/6591 This passes: ``` cargo test --features stdbuf test_stdbuf::test_libstdbuf_preload -- --nocapture ``` This fails: ``` cross test --target aarch64-unknown-linux-gnu --features stdbuf test_stdbuf::test_libstdbuf_preload -- --nocapture ``` Signed-off-by: Etienne Cordonnier --- tests/by-util/test_stdbuf.rs | 73 ++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/by-util/test_stdbuf.rs b/tests/by-util/test_stdbuf.rs index c4294c6af..cbd0a5c2b 100644 --- a/tests/by-util/test_stdbuf.rs +++ b/tests/by-util/test_stdbuf.rs @@ -2,6 +2,13 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +// spell-checker:ignore dyld dylib setvbuf +#[cfg(all( + not(target_os = "windows"), + not(target_os = "openbsd"), + not(target_os = "macos") +))] +use std::process::Command; use uutests::new_ucmd; #[cfg(not(target_os = "windows"))] use uutests::util::TestScenario; @@ -34,6 +41,9 @@ fn test_no_such() { #[test] fn test_stdbuf_unbuffered_stdout() { // This is a basic smoke test + // Note: This test only verifies that stdbuf does not crash and that output is passed through as expected + // for simple, short-lived commands. It does not guarantee that buffering is actually modified or that + // libstdbuf is loaded and functioning correctly. new_ucmd!() .args(&["-o0", "head"]) .pipe_in("The quick brown fox jumps over the lazy dog.") @@ -44,6 +54,9 @@ fn test_stdbuf_unbuffered_stdout() { #[cfg(all(not(target_os = "windows"), not(target_os = "openbsd")))] #[test] fn test_stdbuf_line_buffered_stdout() { + // Note: This test only verifies that stdbuf does not crash and that output is passed through as expected + // for simple, short-lived commands. It does not guarantee that buffering is actually modified or that + // libstdbuf is loaded and functioning correctly. new_ucmd!() .args(&["-oL", "head"]) .pipe_in("The quick brown fox jumps over the lazy dog.") @@ -105,3 +118,63 @@ fn test_stdbuf_invalid_mode_fails() { } } } + +// macos uses DYLD_PRINT_LIBRARIES, not LD_DEBUG, so disable on macos at the moment +#[cfg(all( + not(target_os = "windows"), + not(target_os = "openbsd"), + not(target_os = "macos") +))] +#[test] +fn test_setvbuf_resolution() { + // Run a simple program with LD_DEBUG=symbols to see which setvbuf is being used + // Written in a way that it can run with cross-rs and be used as regression test + // for https://github.com/uutils/coreutils/issues/6591 + + let scene = TestScenario::new(util_name!()); + let coreutils_bin = &scene.bin_path; + + // Test with our own echo (should have the correct architecture even when cross-compiled using cross-rs, + // in which case the "system" echo will be the host architecture) + let uutils_echo_cmd = format!( + "LD_DEBUG=symbols {} stdbuf -oL {} echo test 2>&1", + coreutils_bin.display(), + coreutils_bin.display() + ); + let uutils_output = Command::new("sh") + .arg("-c") + .arg(&uutils_echo_cmd) + .output() + .expect("Failed to run uutils echo test"); + + let uutils_debug = String::from_utf8_lossy(&uutils_output.stdout); + + // Check if libstdbuf.so / libstdbuf.dylib is in the lookup path. The log should contain something like this: + // "symbol=setvbuf; lookup in file=/tmp/.tmp0mfmCg/libstdbuf.so [0]" + let libstdbuf_in_path = uutils_debug.contains("symbol=setvbuf") + && uutils_debug.contains("lookup in file=") + && uutils_debug.contains("libstdbuf"); + + // Check for lack of architecture mismatch error. The potential error message is: + // "ERROR: ld.so: object '/tmp/.tmpCLq8jl/libstdbuf.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored." + let arch_mismatch_line = uutils_debug + .lines() + .find(|line| line.contains("cannot be preloaded")); + println!("LD_DEBUG output: {}", uutils_debug); + let no_arch_mismatch = arch_mismatch_line.is_none(); + + println!("libstdbuf in lookup path: {}", libstdbuf_in_path); + println!("No architecture mismatch: {}", no_arch_mismatch); + if let Some(error_line) = arch_mismatch_line { + println!("Architecture mismatch error: {}", error_line); + } + + assert!( + libstdbuf_in_path, + "libstdbuf should be in lookup path with uutils echo" + ); + assert!( + no_arch_mismatch, + "uutils echo should not show architecture mismatch" + ); +} From 35634b46a0acfc9028743bf023c133a4d0135f13 Mon Sep 17 00:00:00 2001 From: Etienne Cordonnier Date: Wed, 7 May 2025 20:01:49 +0200 Subject: [PATCH 2/2] stdbuf: fix cross-compilation Summary: Partial fix for https://github.com/uutils/coreutils/issues/6591 The current code declare libstdbuf as a build-dependency of stdbuf as a workaround to enforce that libstdbuf is compiled before stdbuf. This breaks cross-compilation, because build-dependencies were compiled for the host architecture, and not for the target architecture. The reason this workaround is necessary is that bindeps is available only in nightly at the moment: https://rust-lang.github.io/rfcs/3028-cargo-binary-dependencies.html This commit replaces the "build-dependency" workaround with another workaround: calling cargo manually to build libstdbuf in the build.rs of stdbuf, in order to ensure that libstdbuf is built before stdbuf. Changes: - Removed cpp/cpp_build dependencies: The cpp, cpp_build, and related dependencies were removed because they made cross-compilation in a build.rs file very complex, since you need to pass proper CXX env variables for cross-compilation, whereas cross-compiling rust code using cargo is quite simple. Provided Rust implementations for getting stdin, stdout, and stderr pointers. Switched from C++/cpp macro-based initialization to using the Rust ctor crate for library initialization. - Remove "feat_require_crate_cpp" which is not needed any more, since stdbuf was the only utility using the cpp crate. Tests: This commit fixes e.g. this test: cross test --target aarch64-unknown-linux-gnu --features stdbuf test_stdbuf::test_libstdbuf_preload -- --nocapture - The "i686" build of stdbuf was also broken (stdbuf 32 bits, but libstdbuf 64 bits) and test_stdbuf::test_libstdbuf_preload of the i686 builds in github CI serves as regression test for this issue, no need to add a cross-rs test for aarch64. - The x86_64 musl build of stdbuf was also broken and was passing tests in CI only because it was compiled with the wrong libc (glibc instead of musl) Signed-off-by: Etienne Cordonnier --- .cargo/config.toml | 5 + Cargo.lock | 379 ++++++++++--------- Cargo.toml | 11 +- deny.toml | 38 +- src/uu/stdbuf/Cargo.toml | 4 +- src/uu/stdbuf/build.rs | 106 ++++-- src/uu/stdbuf/src/libstdbuf/Cargo.toml | 10 +- src/uu/stdbuf/src/libstdbuf/build.rs | 14 +- src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs | 88 ++++- src/uu/stdbuf/src/stdbuf.rs | 10 + tests/by-util/test_stdbuf.rs | 78 +++- 11 files changed, 476 insertions(+), 267 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index c6aa20761..02550b267 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,3 +3,8 @@ linker = "x86_64-unknown-redox-gcc" [env] PROJECT_NAME_FOR_VERSION_STRING = "uutils coreutils" + +# libstdbuf must be a shared library, so musl libc can't be linked statically +# https://github.com/rust-lang/rust/issues/82193 +[build] +rustflags = [ "-C", "target-feature=-crt-static" ] diff --git a/Cargo.lock b/Cargo.lock index 4e2b95dbd..1e9ebde10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,12 +88,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] @@ -172,7 +172,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -194,9 +194,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitvec" @@ -274,9 +274,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "shlex", ] @@ -412,7 +412,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "tiny-keccak", ] @@ -579,56 +579,6 @@ dependencies = [ "zip", ] -[[package]] -name = "cpp" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bcac3d8234c1fb813358e83d1bb6b0290a3d2b3b5efc6b88bfeaf9d8eec17" -dependencies = [ - "cpp_macros", -] - -[[package]] -name = "cpp_build" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f8638c97fbd79cc6fc80b616e0e74b49bac21014faed590bbc89b7e2676c90" -dependencies = [ - "cc", - "cpp_common", - "lazy_static", - "proc-macro2", - "regex", - "syn", - "unicode-xid", -] - -[[package]] -name = "cpp_common" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25fcfea2ee05889597d35e986c2ad0169694320ae5cc8f6d2640a4bb8a884560" -dependencies = [ - "lazy_static", - "proc-macro2", - "syn", -] - -[[package]] -name = "cpp_macros" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d156158fe86e274820f5a53bc9edb0885a6e7113909497aa8d883b69dd171871" -dependencies = [ - "aho-corasick", - "byteorder", - "cpp_common", - "lazy_static", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -678,7 +628,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "crossterm_winapi", "derive_more", "document-features", @@ -907,9 +857,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -921,7 +871,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22be12de19decddab85d09f251ec8363f060ccb22ec9c81bc157c0c8433946d8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "log", "scopeguard", "uuid", @@ -1026,9 +976,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "fs_extra" @@ -1122,9 +1072,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1133,14 +1083,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -1167,9 +1117,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -1225,12 +1175,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1252,7 +1202,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "inotify-sys", "libc", ] @@ -1317,9 +1267,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e77966151130221b079bcec80f1f34a9e414fa489d99152a201c07fd2182bc" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -1332,9 +1282,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97265751f8a9a4228476f2fc17874a9e7e70e96b893368e42619880fe143b48a" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", @@ -1377,9 +1327,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.0.8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" dependencies = [ "kqueue-sys", "libc", @@ -1395,12 +1345,6 @@ dependencies = [ "libc", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "libc" version = "0.2.172" @@ -1409,19 +1353,19 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.53.0", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" @@ -1429,7 +1373,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "redox_syscall", ] @@ -1457,25 +1401,19 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" @@ -1483,7 +1421,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1529,23 +1467,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1554,7 +1492,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "cfg_aliases", "libc", @@ -1585,7 +1523,7 @@ version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "filetime", "fsevent-sys", "inotify", @@ -1692,9 +1630,15 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "onig" @@ -1702,7 +1646,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "once_cell", "onig_sys", @@ -1739,9 +1683,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -1749,9 +1693,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -1860,11 +1804,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.25", ] [[package]] @@ -1879,9 +1823,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.30" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", "syn", @@ -1920,6 +1864,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -1973,7 +1923,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -1982,7 +1932,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", ] [[package]] @@ -2007,11 +1957,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -2122,11 +2072,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.1" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", @@ -2135,9 +2085,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "same-file" @@ -2166,7 +2116,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e37f432dfe840521abd9a72fefdf88ed7ad0f43bbea7d9d1d3d80383e9f4ad13" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "once_cell", "parking_lot", @@ -2282,9 +2232,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -2333,9 +2283,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2349,9 +2299,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.99" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -2371,7 +2321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2577,12 +2527,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "unindent" version = "0.2.4" @@ -2612,7 +2556,7 @@ dependencies = [ "thiserror 1.0.69", "time", "utmp-classic-raw", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -2622,7 +2566,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c226537a3d6e01c440c1926ca0256dbee2d19b2229ede6fc4863a6493dd831" dependencies = [ "cfg-if", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -3399,8 +3343,7 @@ dependencies = [ name = "uu_stdbuf_libstdbuf" version = "0.1.0" dependencies = [ - "cpp", - "cpp_build", + "ctor", "libc", ] @@ -3709,9 +3652,13 @@ version = "0.1.0" [[package]] name = "uuid" -version = "1.15.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "uutests" @@ -3770,9 +3717,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -3876,7 +3823,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -3887,9 +3834,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.60.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", @@ -3900,9 +3847,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.59.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", @@ -3928,18 +3875,18 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-result" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -3995,13 +3942,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -4014,6 +3977,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -4026,6 +3995,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -4038,12 +4013,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -4056,6 +4043,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -4068,6 +4061,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -4080,6 +4079,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -4092,6 +4097,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.10" @@ -4103,11 +4114,11 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -4148,7 +4159,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive 0.8.25", ] [[package]] @@ -4162,6 +4182,17 @@ dependencies = [ "syn", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.6" @@ -4199,14 +4230,12 @@ checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" [[package]] name = "zopfli" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index cec7ae21c..a69100fea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -158,7 +158,6 @@ feat_os_macos = [ feat_os_unix = [ "feat_Tier1", # - "feat_require_crate_cpp", "feat_require_unix", "feat_require_unix_utmpx", "feat_require_unix_hostid", @@ -185,9 +184,7 @@ feat_os_unix_android = [ # # ** NOTE: these `feat_require_...` sets should be minimized as much as possible to encourage cross-platform availability of utilities # -# "feat_require_crate_cpp" == set of utilities requiring the `cpp` crate (which fail to compile on several platforms; as of 2020-04-23) -feat_require_crate_cpp = ["stdbuf"] -# "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23) +# "feat_require_unix" == set of utilities requiring support which is only available on unix platforms feat_require_unix = [ "chgrp", "chmod", @@ -204,6 +201,7 @@ feat_require_unix = [ "nohup", "pathchk", "stat", + "stdbuf", "stty", "timeout", "tty", @@ -220,8 +218,6 @@ feat_require_selinux = ["chcon", "runcon"] feat_os_unix_fuchsia = [ "feat_common_core", # - "feat_require_crate_cpp", - # "chgrp", "chmod", "chown", @@ -287,6 +283,7 @@ clap_complete = "4.4" clap_mangen = "0.2" compare = "0.1.0" crossterm = "0.29.0" +ctor = "0.4.1" ctrlc = { version = "3.4.7", features = ["termination"] } dns-lookup = { version = "2.0.4" } exacl = "0.12.0" @@ -502,6 +499,7 @@ yes = { optional = true, version = "0.1.0", package = "uu_yes", path = "src/uu/y [dev-dependencies] chrono = { workspace = true } +ctor = { workspace = true } filetime = { workspace = true } glob = { workspace = true } libc = { workspace = true } @@ -524,7 +522,6 @@ uucore = { workspace = true, features = [ walkdir = { workspace = true } hex-literal = "1.0.0" rstest = { workspace = true } -ctor = "0.4.1" [target.'cfg(unix)'.dev-dependencies] nix = { workspace = true, features = ["process", "signal", "user", "term"] } diff --git a/deny.toml b/deny.toml index 1b1700dcd..c15502149 100644 --- a/deny.toml +++ b/deny.toml @@ -58,22 +58,42 @@ skip = [ { name = "windows-sys", version = "0.48.0" }, # mio, nu-ansi-term, socket2 { name = "windows-sys", version = "0.52.0" }, + # anstyle-query + { name = "windows-sys", version = "0.59.0" }, # windows-sys - { name = "windows-targets", version = "0.48.0" }, + { name = "windows-targets", version = "0.48.5" }, + # parking_lot_core + { name = "windows-targets", version = "0.52.6" }, # windows-targets - { name = "windows_aarch64_gnullvm", version = "0.48.0" }, + { name = "windows_aarch64_gnullvm", version = "0.48.5" }, # windows-targets - { name = "windows_aarch64_msvc", version = "0.48.0" }, + { name = "windows_aarch64_gnullvm", version = "0.52.6" }, # windows-targets - { name = "windows_i686_gnu", version = "0.48.0" }, + { name = "windows_aarch64_msvc", version = "0.48.5" }, # windows-targets - { name = "windows_i686_msvc", version = "0.48.0" }, + { name = "windows_aarch64_msvc", version = "0.52.6" }, # windows-targets - { name = "windows_x86_64_gnu", version = "0.48.0" }, + { name = "windows_i686_gnu", version = "0.48.5" }, # windows-targets - { name = "windows_x86_64_gnullvm", version = "0.48.0" }, + { name = "windows_i686_gnu", version = "0.52.6" }, # windows-targets - { name = "windows_x86_64_msvc", version = "0.48.0" }, + { name = "windows_i686_gnullvm", version = "0.52.6" }, + # windows-targets + { name = "windows_i686_msvc", version = "0.48.5" }, + # windows-targets + { name = "windows_i686_msvc", version = "0.52.6" }, + # windows-targets + { name = "windows_x86_64_gnu", version = "0.48.5" }, + # windows-targets + { name = "windows_x86_64_gnu", version = "0.52.6" }, + # windows-targets + { name = "windows_x86_64_gnullvm", version = "0.48.5" }, + # windows-targets + { name = "windows_x86_64_gnullvm", version = "0.52.6" }, + # windows-targets + { name = "windows_x86_64_msvc", version = "0.48.5" }, + # windows-targets + { name = "windows_x86_64_msvc", version = "0.52.6" }, # kqueue-sys, onig { name = "bitflags", version = "1.3.2" }, # ansi-width @@ -98,6 +118,8 @@ skip = [ { name = "rand_chacha", version = "0.3.1" }, # rand { name = "rand_core", version = "0.6.4" }, + # utmp-classic + { name = "zerocopy", version = "0.7.35" }, ] # spell-checker: enable diff --git a/src/uu/stdbuf/Cargo.toml b/src/uu/stdbuf/Cargo.toml index 5f9e8ffd7..bcfc9fb94 100644 --- a/src/uu/stdbuf/Cargo.toml +++ b/src/uu/stdbuf/Cargo.toml @@ -19,12 +19,10 @@ path = "src/stdbuf.rs" [dependencies] clap = { workspace = true } +libstdbuf = { package = "uu_stdbuf_libstdbuf", path = "src/libstdbuf" } tempfile = { workspace = true } uucore = { workspace = true, features = ["parser"] } -[build-dependencies] -libstdbuf = { version = "0.1.0", package = "uu_stdbuf_libstdbuf", path = "src/libstdbuf" } - [[bin]] name = "stdbuf" path = "src/main.rs" diff --git a/src/uu/stdbuf/build.rs b/src/uu/stdbuf/build.rs index b31a32235..abb4069ad 100644 --- a/src/uu/stdbuf/build.rs +++ b/src/uu/stdbuf/build.rs @@ -2,14 +2,20 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (ToDO) dylib libstdbuf deps liblibstdbuf +// spell-checker:ignore (ToDO) bindeps dylib libstdbuf deps liblibstdbuf use std::env; -use std::env::current_exe; use std::fs; use std::path::Path; +use std::process::Command; -#[cfg(not(any(target_vendor = "apple", target_os = "windows")))] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly" +))] mod platform { pub const DYLIB_EXT: &str = ".so"; } @@ -19,31 +25,83 @@ mod platform { pub const DYLIB_EXT: &str = ".dylib"; } -#[cfg(target_os = "windows")] -mod platform { - pub const DYLIB_EXT: &str = ".dll"; -} - fn main() { - let current_exe = current_exe().unwrap(); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=src/libstdbuf/src/libstdbuf.rs"); - let out_dir_string = env::var("OUT_DIR").unwrap(); - let out_dir = Path::new(&out_dir_string); + let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set"); + let target = env::var("TARGET").unwrap_or_else(|_| "unknown".to_string()); - let deps_dir = current_exe.ancestors().nth(3).unwrap().join("deps"); - dbg!(&deps_dir); + // Create a separate build directory for libstdbuf to avoid conflicts + let build_dir = Path::new(&out_dir).join("libstdbuf-build"); + fs::create_dir_all(&build_dir).expect("Failed to create build directory"); - let libstdbuf = deps_dir - .read_dir() - .unwrap() - .flatten() - .find(|entry| { - let n = entry.file_name(); - let name = n.to_string_lossy(); + // Get the cargo executable + let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); - name.starts_with("liblibstdbuf") && name.ends_with(platform::DYLIB_EXT) - }) - .expect("unable to find libstdbuf"); + // This manual cargo call ensures that libstdbuf is built before stdbuf.rs is compiled, which is necessary + // for include_bytes!(..."/libstdbuf.so") to work. + // In the future, "bindeps" should be used to simplify the code and avoid the manual cargo call, + // however this is available only in cargo nightly at the moment. + // See the tracking issue: https://github.com/rust-lang/cargo/issues/9096 + let mut cmd = Command::new(&cargo); + cmd.env_clear().envs(env::vars()); + cmd.current_dir(Path::new("src/libstdbuf")).args([ + "build", + "--target-dir", + build_dir.to_str().unwrap(), + ]); - fs::copy(libstdbuf.path(), out_dir.join("libstdbuf.so")).unwrap(); + // Get the current profile + let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); + + // Pass the release flag if we're in release mode + if profile == "release" || profile == "bench" { + cmd.arg("--release"); + } + + // Pass the target architecture if we're cross-compiling + if !target.is_empty() && target != "unknown" { + cmd.arg("--target").arg(&target); + } + + let status = cmd.status().expect("Failed to build libstdbuf"); + assert!(status.success(), "Failed to build libstdbuf"); + + // Copy the built library to OUT_DIR for include_bytes! to find + let lib_name = format!("liblibstdbuf{}", platform::DYLIB_EXT); + let dest_path = Path::new(&out_dir).join(format!("libstdbuf{}", platform::DYLIB_EXT)); + + // Check multiple possible locations for the built library + let possible_paths = if !target.is_empty() && target != "unknown" { + vec![ + build_dir.join(&target).join(&profile).join(&lib_name), + build_dir + .join(&target) + .join(&profile) + .join("deps") + .join(&lib_name), + ] + } else { + vec![ + build_dir.join(&profile).join(&lib_name), + build_dir.join(&profile).join("deps").join(&lib_name), + ] + }; + + // Try to find the library in any of the possible locations + let mut found = false; + for source_path in &possible_paths { + if source_path.exists() { + fs::copy(source_path, &dest_path).expect("Failed to copy libstdbuf library"); + found = true; + break; + } + } + + assert!( + found, + "Could not find built libstdbuf library. Searched in: {:?}.", + possible_paths + ); } diff --git a/src/uu/stdbuf/src/libstdbuf/Cargo.toml b/src/uu/stdbuf/src/libstdbuf/Cargo.toml index 3f8511ffa..01dd3a49d 100644 --- a/src/uu/stdbuf/src/libstdbuf/Cargo.toml +++ b/src/uu/stdbuf/src/libstdbuf/Cargo.toml @@ -13,14 +13,8 @@ edition.workspace = true [lib] name = "libstdbuf" path = "src/libstdbuf.rs" -crate-type = [ - "cdylib", - "rlib", -] # XXX: note: the rlib is just to prevent Cargo from spitting out a warning +crate-type = ["cdylib"] [dependencies] -cpp = "0.5.10" +ctor = { workspace = true } libc = { workspace = true } - -[build-dependencies] -cpp_build = "0.5.10" diff --git a/src/uu/stdbuf/src/libstdbuf/build.rs b/src/uu/stdbuf/src/libstdbuf/build.rs index 6dcd6a869..505cdf68a 100644 --- a/src/uu/stdbuf/src/libstdbuf/build.rs +++ b/src/uu/stdbuf/src/libstdbuf/build.rs @@ -4,8 +4,18 @@ // file that was distributed with this source code. // spell-checker:ignore (ToDO) libstdbuf -use cpp_build::Config; +use std::env; fn main() { - Config::new().pic(true).build("src/libstdbuf.rs"); + // Make sure we're building position-independent code for use with LD_PRELOAD + println!("cargo:rustc-link-arg=-fPIC"); + + let target = env::var("TARGET").unwrap_or_else(|_| "unknown".to_string()); + // Ensure the library doesn't have any undefined symbols (-z flag not supported on macOS) + if !target.contains("apple-darwin") { + println!("cargo:rustc-link-arg=-z"); + println!("cargo:rustc-link-arg=defs"); + } + + println!("cargo:rerun-if-changed=src/libstdbuf.rs"); } diff --git a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs index b151ce686..d99509880 100644 --- a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs +++ b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs @@ -2,34 +2,80 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (ToDO) IOFBF IOLBF IONBF cstdio setvbuf +// spell-checker:ignore (ToDO) IOFBF IOLBF IONBF setvbuf stderrp stdinp stdoutp -use cpp::cpp; +use ctor::ctor; use libc::{_IOFBF, _IOLBF, _IONBF, FILE, c_char, c_int, fileno, size_t}; use std::env; use std::ptr; -cpp! {{ - #include +// This runs automatically when the library is loaded via LD_PRELOAD +#[ctor] +fn init() { + unsafe { __stdbuf() }; +} - extern "C" { - void __stdbuf(void); - - void __attribute((constructor)) - __stdbuf_init(void) { - __stdbuf(); +/// # Safety +/// This function is unsafe because it calls a C API +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __stdbuf_get_stdin() -> *mut FILE { + #[cfg(any(target_os = "macos", target_os = "freebsd"))] + { + unsafe extern "C" { + fn __stdinp() -> *mut FILE; } - - FILE *__stdbuf_get_stdin() { return stdin; } - FILE *__stdbuf_get_stdout() { return stdout; } - FILE *__stdbuf_get_stderr() { return stderr; } + unsafe { __stdinp() } } -}} -unsafe extern "C" { - fn __stdbuf_get_stdin() -> *mut FILE; - fn __stdbuf_get_stdout() -> *mut FILE; - fn __stdbuf_get_stderr() -> *mut FILE; + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + { + unsafe extern "C" { + static mut stdin: *mut FILE; + } + unsafe { stdin } + } +} + +/// # Safety +/// This function is unsafe because it calls a C API +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __stdbuf_get_stdout() -> *mut FILE { + #[cfg(any(target_os = "macos", target_os = "freebsd"))] + { + unsafe extern "C" { + fn __stdoutp() -> *mut FILE; + } + unsafe { __stdoutp() } + } + + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + { + unsafe extern "C" { + static mut stdout: *mut FILE; + } + unsafe { stdout } + } +} + +/// # Safety +/// This function is unsafe because it calls a C API +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __stdbuf_get_stderr() -> *mut FILE { + #[cfg(any(target_os = "macos", target_os = "freebsd"))] + { + unsafe extern "C" { + fn __stderrp() -> *mut FILE; + } + unsafe { __stderrp() } + } + + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + { + unsafe extern "C" { + static mut stderr: *mut FILE; + } + unsafe { stderr } + } } fn set_buffer(stream: *mut FILE, value: &str) { @@ -61,7 +107,9 @@ fn set_buffer(stream: *mut FILE, value: &str) { } /// # Safety -/// ToDO ... (safety note) +/// This function is intended to be called automatically when the library is loaded via LD_PRELOAD. +/// It assumes that the standard streams are valid and that calling setvbuf on them is safe. +/// The caller must ensure this function is only called in a compatible runtime environment. #[unsafe(no_mangle)] pub unsafe extern "C" fn __stdbuf() { if let Ok(val) = env::var("_STDBUF_E") { diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 3b5c3fb9d..fa6b2e630 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -31,8 +31,18 @@ mod options { pub const COMMAND: &str = "command"; } +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly" +))] const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.so")); +#[cfg(target_vendor = "apple")] +const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.dylib")); + enum BufferType { Default, Line, diff --git a/tests/by-util/test_stdbuf.rs b/tests/by-util/test_stdbuf.rs index cbd0a5c2b..dec6bfe64 100644 --- a/tests/by-util/test_stdbuf.rs +++ b/tests/by-util/test_stdbuf.rs @@ -3,12 +3,6 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore dyld dylib setvbuf -#[cfg(all( - not(target_os = "windows"), - not(target_os = "openbsd"), - not(target_os = "macos") -))] -use std::process::Command; use uutests::new_ucmd; #[cfg(not(target_os = "windows"))] use uutests::util::TestScenario; @@ -37,7 +31,15 @@ fn test_no_such() { .stderr_contains("No such file or directory"); } -#[cfg(all(not(target_os = "windows"), not(target_os = "openbsd")))] +// Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target +// does not provide musl-compiled system utilities (like head), leading to dynamic linker errors +// when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD. +#[cfg(all( + not(target_os = "windows"), + not(target_os = "freebsd"), + not(target_os = "openbsd"), + not(all(target_arch = "x86_64", target_env = "musl")) +))] #[test] fn test_stdbuf_unbuffered_stdout() { // This is a basic smoke test @@ -51,7 +53,15 @@ fn test_stdbuf_unbuffered_stdout() { .stdout_is("The quick brown fox jumps over the lazy dog."); } -#[cfg(all(not(target_os = "windows"), not(target_os = "openbsd")))] +// Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target +// does not provide musl-compiled system utilities (like head), leading to dynamic linker errors +// when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD. +#[cfg(all( + not(target_os = "windows"), + not(target_os = "freebsd"), + not(target_os = "openbsd"), + not(all(target_arch = "x86_64", target_env = "musl")) +))] #[test] fn test_stdbuf_line_buffered_stdout() { // Note: This test only verifies that stdbuf does not crash and that output is passed through as expected @@ -75,7 +85,15 @@ fn test_stdbuf_no_buffer_option_fails() { .stderr_contains("the following required arguments were not provided:"); } -#[cfg(all(not(target_os = "windows"), not(target_os = "openbsd")))] +// Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target +// does not provide musl-compiled system utilities (like tail), leading to dynamic linker errors +// when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD. +#[cfg(all( + not(target_os = "windows"), + not(target_os = "freebsd"), + not(target_os = "openbsd"), + not(all(target_arch = "x86_64", target_env = "musl")) +))] #[test] fn test_stdbuf_trailing_var_arg() { new_ucmd!() @@ -119,16 +137,25 @@ fn test_stdbuf_invalid_mode_fails() { } } -// macos uses DYLD_PRINT_LIBRARIES, not LD_DEBUG, so disable on macos at the moment +// macos uses DYLD_PRINT_LIBRARIES, not LD_DEBUG, so disable on macos at the moment. +// On modern Android (Bionic, API 37+), LD_DEBUG is supported and behaves similarly to glibc. +// On older Android versions (Bionic, API < 37), LD_DEBUG uses integer values instead of strings +// and is sometimes disabled. Disable test on Android for now. +// musl libc dynamic loader does not support LD_DEBUG, so disable on musl targets as well. #[cfg(all( not(target_os = "windows"), not(target_os = "openbsd"), - not(target_os = "macos") + not(target_os = "macos"), + not(target_os = "android"), + not(target_env = "musl") ))] #[test] -fn test_setvbuf_resolution() { - // Run a simple program with LD_DEBUG=symbols to see which setvbuf is being used - // Written in a way that it can run with cross-rs and be used as regression test +fn test_libstdbuf_preload() { + use std::process::Command; + + // Run a simple program with LD_DEBUG=symbols to verify that libstdbuf is loaded correctly + // and that there are no architecture mismatches when preloading the library. + // Note: This does not check which setvbuf implementation is used, as our libstdbuf does not override setvbuf. // for https://github.com/uutils/coreutils/issues/6591 let scene = TestScenario::new(util_name!()); @@ -149,13 +176,24 @@ fn test_setvbuf_resolution() { let uutils_debug = String::from_utf8_lossy(&uutils_output.stdout); - // Check if libstdbuf.so / libstdbuf.dylib is in the lookup path. The log should contain something like this: - // "symbol=setvbuf; lookup in file=/tmp/.tmp0mfmCg/libstdbuf.so [0]" - let libstdbuf_in_path = uutils_debug.contains("symbol=setvbuf") - && uutils_debug.contains("lookup in file=") - && uutils_debug.contains("libstdbuf"); + // Check if libstdbuf.so / libstdbuf.dylib is in the lookup path. + // With GLIBC, the log should contain something like: + // "symbol=setvbuf; lookup in file=/tmp/.tmp0mfmCg/libstdbuf.so [0]" + // With FreeBSD dynamic loader, the log should contain something like: + // cspell:disable-next-line + // "calling init function for /tmp/.tmpu11rhP/libstdbuf.so at ..." + let libstdbuf_in_path = if cfg!(target_os = "freebsd") { + uutils_debug + .lines() + .any(|line| line.contains("calling init function") && line.contains("libstdbuf")) + } else { + uutils_debug.contains("symbol=setvbuf") + && uutils_debug.contains("lookup in file=") + && uutils_debug.contains("libstdbuf") + }; - // Check for lack of architecture mismatch error. The potential error message is: + // Check for lack of architecture mismatch error. The potential error message with GLIBC is: + // cspell:disable-next-line // "ERROR: ld.so: object '/tmp/.tmpCLq8jl/libstdbuf.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored." let arch_mismatch_line = uutils_debug .lines()