diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index ef6e5f9..6e980ad 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -52,7 +52,7 @@ jobs: components: clippy - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.9 + uses: mozilla-actions/sccache-action@v0.0.10 - if: ${{ contains(matrix.job.os, 'ubuntu') }} run: | sudo apt-get update -y diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f4b1ac7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Contributing to procps + +Hi! Welcome to uutils/procps, and thanks for wanting to contribute! + +This project follows the shared conventions of the [uutils](https://github.com/uutils) +organization. Before opening a pull request, please read: + +- Our **[Review Guidelines](https://uutils.github.io/reviews/)** — what we expect + from a pull request and how reviews are carried out. +- Our community's [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md), if present. + +Finally, feel free to join our [Discord](https://discord.gg/wQVJbvJ)! + +> [!WARNING] +> uutils is original code and cannot contain any code from GNU or other +> strongly-licensed (GPL/LGPL) implementations. We **cannot** accept changes +> based on the GNU source code, and you **must not link** to it either. You may +> look at permissively-licensed implementations (MIT/BSD) and read the GNU +> *manuals* — never the GNU *source*. + +## In short + +- Discuss non-trivial changes in an issue **before** writing the code. +- Keep pull requests **small, self-contained, and descriptively titled** + (e.g. `procps: fix ...`). +- Make sure CI passes: tests are green, `rustfmt` is satisfied, and there are + no `clippy` warnings. +- Add tests for new behavior; don't let coverage regress. +- Write small, atomic commits annotated with the component you touched. + +See the [Review Guidelines](https://uutils.github.io/reviews/) for the full +details. diff --git a/Cargo.lock b/Cargo.lock index d1e6c84..6470b61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", ] @@ -240,9 +240,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.6.1" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406e68b4de5c59cfb8f750a7cbd4d31ae153788b8352167c1e5f4fc26e8c91e9" +checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" dependencies = [ "clap", ] @@ -390,19 +390,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" dependencies = [ - "ctor-proc-macro 0.0.7", - "dtor 0.3.0", + "ctor-proc-macro", + "dtor", ] [[package]] name = "ctor" -version = "0.9.1" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c888a2a4f677017373fb6c01e13e318dd9e78758445ed5eb985e355d3f8281" +checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a" dependencies = [ - "ctor-proc-macro 0.0.12", - "dtor 0.6.0", "link-section", + "linktime-proc-macro", ] [[package]] @@ -411,12 +410,6 @@ version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" -[[package]] -name = "ctor-proc-macro" -version = "0.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ab264ea985f1bd27887d7b21ea2bb046728e05d11909ca138d700c494730db" - [[package]] name = "darling" version = "0.20.11" @@ -546,6 +539,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.10.0", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -584,16 +587,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" dependencies = [ - "dtor-proc-macro 0.0.6", -] - -[[package]] -name = "dtor" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e4690622ab6700ced40fc370a3f07b7d111f0154bb6fb08f73b4c8834f75b6" -dependencies = [ - "dtor-proc-macro 0.0.12", + "dtor-proc-macro", ] [[package]] @@ -602,12 +596,6 @@ version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" -[[package]] -name = "dtor-proc-macro" -version = "0.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c98b077c7463d01d22dde8a24378ddf1ca7263dc687cffbed38819ea6c21131" - [[package]] name = "either" version = "1.15.0" @@ -976,9 +964,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -986,14 +974,14 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-link", ] [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -1081,9 +1069,15 @@ dependencies = [ [[package]] name = "link-section" -version = "0.0.12" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52437d47b0358721ec869cc7374b2a21f7b2237af9b439c0391341a1fbfbf1b" +checksum = "7a63f9687974de7e2caf6c96a1b19c6e882db299fdde09075c5b9e11c58421cd" + +[[package]] +name = "linktime-proc-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7b0a3383c2a1002d11349c92c85a666a5fb679e96c79d782cf0dbe557fd6ee" [[package]] name = "linux-raw-sys" @@ -1261,6 +1255,15 @@ dependencies = [ "libc", ] +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-core-foundation" version = "0.3.2" @@ -1268,6 +1271,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.10.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.10.0", + "objc2", ] [[package]] @@ -1280,6 +1301,17 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-open-directory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb82bed227edf5201dfedf072bba4015a33d3d4a98519837295a90f0a23f676d" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -1551,7 +1583,7 @@ dependencies = [ "clap", "clap_complete", "clap_mangen", - "ctor 0.9.1", + "ctor 1.0.7", "jiff", "phf 0.13.1", "phf_codegen 0.13.1", @@ -2025,15 +2057,16 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.38.4" +version = "0.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" +checksum = "21d0d938c10fcda3e897e28aaddf4ab462375d411f4378cd63b1c945f69aba96" dependencies = [ "libc", "memchr", "ntapi", "objc2-core-foundation", "objc2-io-kit", + "objc2-open-directory", "windows", ] @@ -2044,7 +2077,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", "rustix", "windows-sys 0.61.2", @@ -2361,6 +2394,7 @@ dependencies = [ name = "uu_hugetop" version = "0.0.1" dependencies = [ + "chrono", "clap", "tempfile", "uucore 0.7.0", diff --git a/Cargo.toml b/Cargo.toml index 77bd865..9fb898a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ clap = { version = "4.5.4", features = ["wrap_help", "cargo", "env"] } clap_complete = "4.5.2" clap_mangen = "0.3.0" crossterm = "0.29.0" -ctor = "0.9.0" +ctor = "1.0.0" dirs = "6.0.0" jiff = "0.2.15" nix = { version = "0.30", default-features = false, features = ["process"] } @@ -72,7 +72,7 @@ rand = { version = "0.10.0" } ratatui = "0.30.0" regex = "1.10.4" rustix = { version = "1.1.2", features = ["fs", "process", "param"] } -sysinfo = "0.38.0" +sysinfo = "0.39.0" tempfile = "3.10.1" terminal_size = "0.4.2" textwrap = { version = "0.16.1", features = ["terminal_size"] } diff --git a/src/uu/hugetop/Cargo.toml b/src/uu/hugetop/Cargo.toml index aa0eea4..983bfea 100644 --- a/src/uu/hugetop/Cargo.toml +++ b/src/uu/hugetop/Cargo.toml @@ -14,6 +14,7 @@ version.workspace = true workspace = true [dependencies] +chrono = { workspace = true } clap = { workspace = true } uucore = { workspace = true } diff --git a/src/uu/hugetop/src/hugetop.rs b/src/uu/hugetop/src/hugetop.rs index ee17ed5..53c6fed 100644 --- a/src/uu/hugetop/src/hugetop.rs +++ b/src/uu/hugetop/src/hugetop.rs @@ -3,12 +3,13 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use chrono::{DateTime, Local}; use clap::{value_parser, Arg, Command}; use std::collections::BTreeMap; use std::fs; use std::path::Path; use std::thread::sleep; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::time::Duration; use uucore::error::UResult; const DEFAULT_HUGEPAGES_ROOT: &str = "/sys/kernel/mm/hugepages"; @@ -122,12 +123,8 @@ pub fn uu_app() -> Command { } fn print_summary(numa: bool, human: bool) { - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map(|d| d.as_secs()) - .unwrap_or_default(); - - println!("hugetop - {}", now); + let now: DateTime = Local::now(); + println!("hugetop - {}", now.format("%a %b %e %T %Y")); let pools = match read_node_hugepage_pools() { Ok(nodes) if numa => { diff --git a/src/uu/pgrep/src/process_matcher.rs b/src/uu/pgrep/src/process_matcher.rs index c991092..e82ef1a 100644 --- a/src/uu/pgrep/src/process_matcher.rs +++ b/src/uu/pgrep/src/process_matcher.rs @@ -405,9 +405,9 @@ fn process_flag_o_n( .collect::>(); if settings.newest { - filtered.sort_by(|a, b| b.pid.cmp(&a.pid)); + filtered.sort_by_key(|b| std::cmp::Reverse(b.pid)); } else { - filtered.sort_by(|a, b| a.pid.cmp(&b.pid)); + filtered.sort_by_key(|a| a.pid); } vec![filtered.first().cloned().unwrap().clone()] diff --git a/src/uu/pmap/src/smaps_format_parser.rs b/src/uu/pmap/src/smaps_format_parser.rs index f478916..1ece26c 100644 --- a/src/uu/pmap/src/smaps_format_parser.rs +++ b/src/uu/pmap/src/smaps_format_parser.rs @@ -316,10 +316,8 @@ pub fn parse_smaps(contents: &str) -> Result { let val = val.strip_suffix(" kB").unwrap_or(val); let val = get_smap_item_value(val)?; match key { - pmap_field_name::SIZE => { - if smap_entry.map_line.size_in_kb != val { - return Err(Error::from(ErrorKind::InvalidData)); - } + pmap_field_name::SIZE if smap_entry.map_line.size_in_kb != val => { + return Err(Error::from(ErrorKind::InvalidData)); } pmap_field_name::KERNEL_PAGE_SIZE => { smap_entry.kernel_page_size_in_kb = val; diff --git a/src/uu/ps/src/process_selection.rs b/src/uu/ps/src/process_selection.rs index c2a0a5a..5cacf00 100644 --- a/src/uu/ps/src/process_selection.rs +++ b/src/uu/ps/src/process_selection.rs @@ -71,7 +71,7 @@ pub struct ProcessSelectionSettings { impl ProcessSelectionSettings { pub fn from_matches(matches: &ArgMatches) -> Self { Self { - select_all: matches.get_flag("A"), + select_all: matches.get_flag("A") || matches.get_flag("e"), select_non_session_leaders_with_tty: matches.get_flag("a"), select_non_session_leaders: matches.get_flag("d"), dont_require_tty: matches.get_flag("x"), diff --git a/src/uu/ps/src/ps.rs b/src/uu/ps/src/ps.rs index 8254811..5ee1af3 100644 --- a/src/uu/ps/src/ps.rs +++ b/src/uu/ps/src/ps.rs @@ -202,7 +202,10 @@ pub fn uu_app() -> Command { Arg::new("A") .short('A') .help("all processes") - .visible_short_alias('e') + .action(ArgAction::SetTrue), + Arg::new("e") + .short('e') + .help("Select all processes. Identical to -A") .action(ArgAction::SetTrue), Arg::new("a") .short('a') diff --git a/src/uu/ps/src/sorting.rs b/src/uu/ps/src/sorting.rs index bed4946..5e90d0a 100644 --- a/src/uu/ps/src/sorting.rs +++ b/src/uu/ps/src/sorting.rs @@ -13,5 +13,5 @@ pub(crate) fn sort(input: &mut [ProcessInformation], _matches: &ArgMatches) { /// Sort by pid. (Default) fn sort_by_pid(input: &mut [ProcessInformation]) { - input.sort_by(|a, b| a.pid.cmp(&b.pid)); + input.sort_by_key(|a| a.pid); } diff --git a/src/uu/vmstat/src/parser.rs b/src/uu/vmstat/src/parser.rs index 63fdcf2..728010d 100644 --- a/src/uu/vmstat/src/parser.rs +++ b/src/uu/vmstat/src/parser.rs @@ -211,6 +211,16 @@ pub struct Meminfo { pub swap_total: bytesize::ByteSize, pub swap_free: bytesize::ByteSize, } + +#[cfg(target_os = "linux")] +fn kb_to_kib(mut size: bytesize::ByteSize) -> bytesize::ByteSize { + // "kB" means KiB instead of KB + // Convert from 1000-based(parsed by bytesize from "kB" ended string) to 1024-based(which it actually is) + // See more at https://github.com/uutils/procps/issues/667 + size.0 = size.0 / 1000 * 1024; + size +} + #[cfg(target_os = "linux")] impl Meminfo { pub fn current() -> Self { @@ -221,20 +231,28 @@ impl Meminfo { pub fn from_proc_map(proc_map: &HashMap) -> Self { use std::str::FromStr; - let mem_total = bytesize::ByteSize::from_str(proc_map.get("MemTotal").unwrap()).unwrap(); - let mem_free = bytesize::ByteSize::from_str(proc_map.get("MemFree").unwrap()).unwrap(); + let mem_total = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("MemTotal").unwrap()).unwrap()); + let mem_free = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("MemFree").unwrap()).unwrap()); let mem_available = - bytesize::ByteSize::from_str(proc_map.get("MemAvailable").unwrap()).unwrap(); - let buffers = bytesize::ByteSize::from_str(proc_map.get("Buffers").unwrap()).unwrap(); - let cached = bytesize::ByteSize::from_str(proc_map.get("Cached").unwrap()).unwrap(); + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("MemAvailable").unwrap()).unwrap()); + let buffers = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("Buffers").unwrap()).unwrap()); + let cached = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("Cached").unwrap()).unwrap()); let s_reclaimable = - bytesize::ByteSize::from_str(proc_map.get("SReclaimable").unwrap()).unwrap(); + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("SReclaimable").unwrap()).unwrap()); let swap_cached = - bytesize::ByteSize::from_str(proc_map.get("SwapCached").unwrap()).unwrap(); - let active = bytesize::ByteSize::from_str(proc_map.get("Active").unwrap()).unwrap(); - let inactive = bytesize::ByteSize::from_str(proc_map.get("Inactive").unwrap()).unwrap(); - let swap_total = bytesize::ByteSize::from_str(proc_map.get("SwapTotal").unwrap()).unwrap(); - let swap_free = bytesize::ByteSize::from_str(proc_map.get("SwapFree").unwrap()).unwrap(); + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("SwapCached").unwrap()).unwrap()); + let active = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("Active").unwrap()).unwrap()); + let inactive = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("Inactive").unwrap()).unwrap()); + let swap_total = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("SwapTotal").unwrap()).unwrap()); + let swap_free = + kb_to_kib(bytesize::ByteSize::from_str(proc_map.get("SwapFree").unwrap()).unwrap()); Self { mem_total, mem_free, @@ -258,7 +276,7 @@ pub struct DiskStatParseError; #[cfg(target_os = "linux")] impl Display for DiskStatParseError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt("Failed to parse diskstat line", f) + Debug::fmt("Failed to parse diskstat line", f) } } diff --git a/tests/by-util/test_ps.rs b/tests/by-util/test_ps.rs index 03ffd7a..c8ec6d3 100644 --- a/tests/by-util/test_ps.rs +++ b/tests/by-util/test_ps.rs @@ -13,9 +13,24 @@ use uucore::process::geteuid; #[test] #[cfg(target_os = "linux")] fn test_select_all_processes() { - for arg in ["-A", "-e"] { - // TODO ensure the output format is correct - new_ucmd!().arg(arg).succeeds(); + let expected_headers = ["PID", "TTY", "TIME", "CMD"]; + + let args_sets = vec![vec!["-A"], vec!["-e"], vec!["-A", "-e"]]; + for args in args_sets { + let result = new_ucmd!().args(&args).succeeds(); + let lines: Vec<&str> = result.stdout_str().lines().collect(); + + assert!( + lines.len() >= 2, + "expected at least a header and one process row" + ); + + let headers: Vec<&str> = lines[0].split_whitespace().collect(); + assert_eq!( + headers, expected_headers, + "unexpected header for args: {:?}", + args + ); } } diff --git a/tests/tests.rs b/tests/tests.rs index a27a429..f9c8076 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -7,7 +7,7 @@ use std::env; pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_procps"); // Use the ctor attribute to run this function before any tests -#[ctor::ctor] +#[ctor::ctor(unsafe)] fn init() { unsafe { // Necessary for uutests to be able to find the binary