procs-0.14.9/.cargo_vcs_info.json0000644000000001360000000000100122550ustar { "git": { "sha1": "a57bf4f6599866ad3015d805ba43b17edc12d3c0" }, "path_in_vcs": "" }procs-0.14.9/.github/FUNDING.yml000064400000000000000000000000771046102023000142260ustar 00000000000000# These are supported funding model platforms github: dalance procs-0.14.9/.github/dependabot.yml000064400000000000000000000002211046102023000152300ustar 00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily time: "20:00" open-pull-requests-limit: 10 procs-0.14.9/.github/workflows/dependabot_merge.yml000064400000000000000000000014741046102023000204570ustar 00000000000000name: Dependabot auto-merge on: pull_request_target permissions: pull-requests: write contents: write jobs: dependabot: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} steps: - name: Dependabot metadata id: metadata uses: dependabot/fetch-metadata@v2.2.0 with: github-token: '${{ secrets.GITHUB_TOKEN }}' - name: Enable auto-merge for Dependabot PRs if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' || ( !startsWith( steps.metadata.outputs.new-version, '0.' ) && steps.metadata.outputs.update-type == 'version-update:semver-minor' ) }} run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} procs-0.14.9/.github/workflows/periodic.yml000064400000000000000000000006771046102023000167750ustar 00000000000000name: Periodic on: schedule: - cron: 0 0 * * SUN jobs: build: strategy: matrix: os: [ubuntu-latest] rust: [stable, beta, nightly] runs-on: ${{ matrix.os }} steps: - name: Setup Rust uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ matrix.rust }} - name: Checkout uses: actions/checkout@v3 - name: Run tests run: | cargo update cargo test procs-0.14.9/.github/workflows/regression.yml000064400000000000000000000037601046102023000173530ustar 00000000000000name: Regression on: push: branches: - master pull_request: jobs: build: strategy: matrix: include: - os: ubuntu-latest rust: stable target: x86_64-unknown-linux-gnu - os: macOS-latest rust: stable target: x86_64-apple-darwin - os: windows-latest rust: stable target: x86_64-pc-windows-msvc runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - name: Run tests run: cargo test --locked --target ${{ matrix.target }} - name: Run tests feature variation run: cargo test --locked --target ${{ matrix.target }} --no-default-features build-freebsd: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: vmactions/freebsd-vm@v1 with: usesh: true prepare: | pkg install -y rust pkg install -y llvm15 run: | cargo test --locked msrv: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@v1 with: toolchain: 1.74.0 targets: x86_64-unknown-linux-gnu - name: Run build run: cargo build rustfmt: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable components: rustfmt - name: Run rustfmt run: cargo fmt -- --check clippy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable components: clippy - name: Run clippy run: cargo clippy -- -D warnings - name: Run clippy feature variation run: cargo clippy --no-default-features -- -D warnings procs-0.14.9/.github/workflows/release.yml000064400000000000000000000025041046102023000166060ustar 00000000000000name: Release on: push: tags: - 'v*.*.*' jobs: build: strategy: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] rust: [stable] runs-on: ${{ matrix.os }} steps: - name: Setup Rust uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ matrix.rust }} - name: Checkout uses: actions/checkout@v3 - name: Setup MUSL if: matrix.os == 'ubuntu-latest' run: | rustup target add x86_64-unknown-linux-musl sudo apt-get -qq install musl-tools - name: Setup aarch64 mac if: matrix.os == 'macOS-latest' run: | rustup target add aarch64-apple-darwin rustup target add x86_64-apple-darwin - name: Build for linux if: matrix.os == 'ubuntu-latest' run: | make release_lnx cargo install --locked cargo-rpm make release_rpm - name: Build for macOS if: matrix.os == 'macOS-latest' run: make release_mac - name: Build for Windows if: matrix.os == 'windows-latest' run: make release_win - name: Release uses: softprops/action-gh-release@v1 with: body: '[Changelog](https://github.com/dalance/procs/blob/master/CHANGELOG.md)' files: "*.zip\n*.rpm" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} procs-0.14.9/.github/workflows/winget.yml000064400000000000000000000006161046102023000164650ustar 00000000000000name: Publish to WinGet on: release: types: [released] workflow_dispatch: jobs: publish: runs-on: windows-latest steps: - uses: vedantmgoyal2009/winget-releaser@v2 with: identifier: dalance.procs max-versions-to-keep: 5 # keep only latest 5 versions installers-regex: 'x86_64-windows\.zip$' token: ${{ secrets.WINGET_TOKEN }} procs-0.14.9/.gitignore000064400000000000000000000000231046102023000130300ustar 00000000000000/target **/*.rs.bk procs-0.14.9/.rpm/procs.spec000064400000000000000000000010201046102023000137140ustar 00000000000000%define __spec_install_post %{nil} %define __os_install_post %{_dbpath}/brp-compress %define debug_package %{nil} Name: procs Summary: A modern replacement for ps Version: @@VERSION@@ Release: @@RELEASE@@ License: MIT Group: Applications/System Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %description %{summary} %prep %setup -q %install rm -rf %{buildroot} mkdir -p %{buildroot} cp -a * %{buildroot} %clean rm -rf %{buildroot} %files %defattr(-,root,root,-) %{_bindir}/* procs-0.14.9/CHANGELOG.md000064400000000000000000000470041046102023000126630ustar 00000000000000# Change Log ## [Unreleased](https://github.com/dalance/procs/compare/v0.14.9...Unreleased) - ReleaseDate ## [v0.14.9](https://github.com/dalance/procs/compare/v0.14.8...v0.14.9) - 2025-01-17 * [Fixed] Build failure on FreeBSD ## [v0.14.8](https://github.com/dalance/procs/compare/v0.14.7...v0.14.8) - 2024-10-23 * [Fixed] Build breaks on FreeBSD [#703](https://github.com/dalance/procs/issues/703) ## [v0.14.7](https://github.com/dalance/procs/compare/v0.14.6...v0.14.7) - 2024-10-22 * [Changed] Header line wrapping [#695](https://github.com/dalance/procs/pull/695) * [Fixed] First key press is ignored [#443](https://github.com/dalance/procs/issues/443) ## [v0.14.6](https://github.com/dalance/procs/compare/v0.14.5...v0.14.6) - 2024-07-30 * [Changed] MSRV to Rust 1.74 * [Added] aarch64-apple-darwin build release ## [v0.14.5](https://github.com/dalance/procs/compare/v0.14.4...v0.14.5) - 2024-03-07 * [Added] Add show_self_parents option [#607](https://github.com/dalance/procs/pull/607) * [Changed] MSRV to Rust 1.70 ## [v0.14.4](https://github.com/dalance/procs/compare/v0.14.3...v0.14.4) - 2023-11-24 * [Fixed] Build breaks on FreeBSD/arm64,i386 ## [v0.14.3](https://github.com/dalance/procs/compare/v0.14.2...v0.14.3) - 2023-10-20 * [Changed] MSRV to Rust 1.67 * [Added] Some columns on FreeBSD ## [v0.14.2](https://github.com/dalance/procs/compare/v0.14.1...v0.14.2) - 2023-10-18 * [Added] BSD support [#313](https://github.com/dalance/procs/issues/313) * [Fixed] wrong time handling on Windows * [Added] User/group cache support * [Added] Cgroup/Ccgroup column [#529](https://github.com/dalance/procs/issues/529) ## [v0.14.1](https://github.com/dalance/procs/compare/v0.14.0...v0.14.1) - 2023-10-06 * [Added] Also look for a config file in /etc/procs/procs.toml [#533](https://github.com/dalance/procs/pull/533) * [Added] less compatible keybinding of built-in pager * [Added] `show_kthreads` config [#446](https://github.com/dalance/procs/pull/446) * [Fixed] procs -i Pid displays Parent PID, not PID, sometimes [#457](https://github.com/dalance/procs/issues/457) ## [v0.14.0](https://github.com/dalance/procs/compare/v0.13.4...v0.14.0) - 2023-03-07 * [Changed] `--config` option to `--gen-config` * [Changed] `--completion` option to `--gen-completion` * [Changed] `--completion-out` option to `--gen-completion-out` * [Added] `--load-config` option to specify config file [#394](https://github.com/dalance/procs/issues/394) * [Added] `--use-config` option to specify built-in config [#152](https://github.com/dalance/procs/pull/152) * [Added] `show_header` and `show_footer` config [#405](https://github.com/dalance/procs/issues/405) * [Added] SecContext column [#260](https://github.com/dalance/procs/issues/260) * [Added] FileName column [#429](https://github.com/dalance/procs/issues/429) * [Added] WorkDir column [#410](https://github.com/dalance/procs/issues/410) * [Added] Env column [#143](https://github.com/dalance/procs/issues/143) * [Added] Built-in pager and Windows pager support [#119](https://github.com/dalance/procs/issues/119) * [Fixed] hang on terminals which ignore DSR request [#288](https://github.com/dalance/procs/issues/288) * [Fixed] Column UserLogin shows 4294967295 [#441](https://github.com/dalance/procs/issues/441) ## [v0.13.4](https://github.com/dalance/procs/compare/v0.13.3...v0.13.4) - 2023-01-29 * [Added] adding sort column to inserts [#396](https://github.com/dalance/procs/pull/396) * [Added] docker: Respect $DOCKER_HOST [#424](https://github.com/dalance/procs/pull/424) ## [v0.13.3](https://github.com/dalance/procs/compare/v0.13.2...v0.13.3) - 2022-10-18 * [Changed] Release zip for Windows has the exe at toplevel ## [v0.13.2](https://github.com/dalance/procs/compare/v0.13.1...v0.13.2) - 2022-10-05 * [Fixed] invalid charset name issue [#366](https://github.com/dalance/procs/issues/366) ## [v0.13.1](https://github.com/dalance/procs/compare/v0.13.0...v0.13.1) - 2022-09-20 * [Added] session column on macOS [#361](https://github.com/dalance/procs/pull/361) ## [v0.13.0](https://github.com/dalance/procs/compare/v0.12.3...v0.13.0) - 2022-07-29 * [Changed] Update procfs to v0.13.0 * [Changed] Use once_cell instead of lazy_static * [Added] Case sensitivity option [#159](https://github.com/dalance/procs/issues/159) * [Added] TreeSlot column [#196](https://github.com/dalance/procs/issues/196) * [Added] Add TcpPort column support for Windows [#318](https://github.com/dalance/procs/pull/318) * [Changed] Update dockworker to v0.0.24 ## [v0.12.3](https://github.com/dalance/procs/compare/v0.12.2...v0.12.3) - 2022-05-25 * [Fixed] Using bash on Emacs, procs-0.12.2 is very slow compared to procs-0.11.13 [#291](https://github.com/dalance/procs/issues/291) ## [v0.12.2](https://github.com/dalance/procs/compare/v0.12.1...v0.12.2) - 2022-05-05 * [Changed] Update Makefile to change release zip names [#279](https://github.com/dalance/procs/pull/279) ## [v0.12.1](https://github.com/dalance/procs/compare/v0.12.0...v0.12.1) - 2022-01-27 * [Fixed] latency based termbg timeout [#221](https://github.com/dalance/procs/issues/221) * [Fixed] wrong decode of cgroup for docker [#236](https://github.com/dalance/procs/issues/236) ## [v0.12.0](https://github.com/dalance/procs/compare/v0.11.13...v0.12.0) - 2022-01-18 * [Changed] Update getch to update termios [#223](https://github.com/dalance/procs/issues/223) * [Changed] Replace structopt with clap * [Fixed] unexpected message at piped [#221](https://github.com/dalance/procs/issues/221) ## [v0.11.13](https://github.com/dalance/procs/compare/v0.11.12...v0.11.13) - 2021-12-24 * [Added] --completion-out option [#219](https://github.com/dalance/procs/pull/219) ## [v0.11.12](https://github.com/dalance/procs/compare/v0.11.11...v0.11.12) - 2021-12-15 * [Fixed] unexpected debug message ## [v0.11.11](https://github.com/dalance/procs/compare/v0.11.10...v0.11.11) - 2021-12-14 * [Fixed] panic when stdout is closed [#210](https://github.com/dalance/procs/issues/210) ## [v0.11.10](https://github.com/dalance/procs/compare/v0.11.9...v0.11.10) - 2021-10-19 * [Added] pgid/session column [#150](https://github.com/dalance/procs/pull/150) * [Added] floating point watch interval support [#157](https://github.com/dalance/procs/pull/157) * [Added] MultiSlot column [#180](https://github.com/dalance/procs/issues/180) * [Fixed] Search failure with only option [#117](https://github.com/dalance/procs/issues/117) * [Added] Show children processes at tree mode [#181](https://github.com/dalance/procs/issues/181) ## [v0.11.9](https://github.com/dalance/procs/compare/v0.11.8...v0.11.9) - 2021-06-22 ## [v0.11.8](https://github.com/dalance/procs/compare/v0.11.7...v0.11.8) - 2021-05-28 ## [v0.11.7](https://github.com/dalance/procs/compare/v0.11.6...v0.11.7) - 2021-05-19 * [Fixed] crash at piped/redirected [#146](https://github.com/dalance/procs/issues/146) * [Added] elapsed time [#120](https://github.com/dalance/procs/issues/120) * [Added] completion file message [#130](https://github.com/dalance/procs/issues/130) ## [v0.11.6](https://github.com/dalance/procs/compare/v0.11.5...v0.11.6) - 2021-05-18 * [Fixed] termbg byte leak ## [v0.11.5](https://github.com/dalance/procs/compare/v0.11.4...v0.11.5) - 2021-05-06 * [Fixed] crash at tree mode [#129](https://github.com/dalance/procs/issues/129) ## [v0.11.4](https://github.com/dalance/procs/compare/v0.11.3...v0.11.4) - 2021-03-12 * [Fixed] suppress theme detection at each refresh of watcher mode ## [v0.11.3](https://github.com/dalance/procs/compare/v0.11.2...v0.11.3) - 2021-01-30 * [Changed] default color for light theme ## [v0.11.2](https://github.com/dalance/procs/compare/v0.11.1...v0.11.2) - 2021-01-29 * [Added] obsolete config check ## [v0.11.1](https://github.com/dalance/procs/compare/v0.11.0...v0.11.1) - 2021-01-28 * [Added] thread information [#30](https://github.com/dalance/procs/issues/30) ## [v0.11.0](https://github.com/dalance/procs/compare/v0.10.10...v0.11.0) - 2021-01-28 * [Added] automatic theme detection [#78](https://github.com/dalance/procs/issues/78) ## [v0.10.10](https://github.com/dalance/procs/compare/v0.10.9...v0.10.10) - 2020-11-26 * [Fixed] broken pager on macOS [#92](https://github.com/dalance/procs/issues/92) ## [v0.10.9](https://github.com/dalance/procs/compare/v0.10.8...v0.10.9) - 2020-11-24 * [Added] --completion option [#86](https://github.com/dalance/procs/issues/86) * [Fixed] crash by --only optiont [#85](https://github.com/dalance/procs/issues/85) ## [v0.10.8](https://github.com/dalance/procs/compare/v0.10.7...v0.10.8) - 2020-11-23 * [Changed] Add `LESSCHARSET=utf-8` by default [#75](https://github.com/dalance/procs/issues/75) ## [v0.10.7](https://github.com/dalance/procs/compare/v0.10.6...v0.10.7) - 2020-11-05 * [Added] detect_width config [#76](https://github.com/dalance/procs/issues/76) ## [v0.10.6](https://github.com/dalance/procs/compare/v0.10.5...v0.10.6) - 2020-11-05 * [Added] --only option [#77](https://github.com/dalance/procs/issues/77) * [Added] --no-header option [#77](https://github.com/dalance/procs/issues/77) ## [v0.10.5](https://github.com/dalance/procs/compare/v0.10.4...v0.10.5) - 2020-09-26 * [Added] LookupAccountSidW caching [#71](https://github.com/dalance/procs/issues/71) * [Changed] Move configuration note to help message [#57](https://github.com/dalance/procs/issues/57) ## [v0.10.4](https://github.com/dalance/procs/compare/v0.10.3...v0.10.4) - 2020-08-10 * [Added] 256 colors support [#67](https://github.com/dalance/procs/issues/67) ## [v0.10.3](https://github.com/dalance/procs/compare/v0.10.2...v0.10.3) - 2020-05-11 * [Changed] Branch filtering of tree view [#59](https://github.com/dalance/procs/issues/59) ## [v0.10.2](https://github.com/dalance/procs/compare/v0.10.1...v0.10.2) - 2020-05-11 * [Changed] Enable XDG config path on macOS [#58](https://github.com/dalance/procs/issues/58) ## [v0.10.1](https://github.com/dalance/procs/compare/v0.10.0...v0.10.1) - 2020-05-01 * [Changed] Enable LTO [#56](https://github.com/dalance/procs/issues/56) ## [v0.10.0](https://github.com/dalance/procs/compare/v0.9.20...v0.10.0) - 2020-04-20 * [Added] header config [#54](https://github.com/dalance/procs/issues/54) * [Changed] simplify default config [#55](https://github.com/dalance/procs/issues/55) ## [v0.9.20](https://github.com/dalance/procs/compare/v0.9.19...v0.9.20) - 2020-03-13 * [Added] Tree color config [#50](https://github.com/dalance/procs/issues/50) * [Added] Black color and style [#49](https://github.com/dalance/procs/issues/49) * [Fixed] broken pipe error ## [v0.9.19](https://github.com/dalance/procs/compare/v0.9.18...v0.9.19) - 2020-03-08 ## [v0.9.18](https://github.com/dalance/procs/compare/v0.9.17...v0.9.18) - 2020-03-05 ## [v0.9.17](https://github.com/dalance/procs/compare/v0.9.16...v0.9.17) - 2020-03-05 * [Changed] update proc-macro-error-attr [#45](https://github.com/dalance/procs/issues/45) ## [v0.9.16](https://github.com/dalance/procs/compare/v0.9.15...v0.9.16) - 2020-03-02 ## [v0.9.15](https://github.com/dalance/procs/compare/v0.9.14...v0.9.15) - 2020-03-02 ## [v0.9.14](https://github.com/dalance/procs/compare/v0.9.13...v0.9.14) - 2020-03-02 ## [v0.9.13](https://github.com/dalance/procs/compare/v0.9.12...v0.9.13) - 2020-03-02 * [Fixed] garbage lines in watch mode ## [v0.9.12](https://github.com/dalance/procs/compare/v0.9.11...v0.9.12) - 2020-02-25 * [Fixed] separator's meaningless sort [#42](https://github.com/dalance/procs/issues/42) ## [v0.9.11](https://github.com/dalance/procs/compare/v0.9.10...v0.9.11) - 2020-02-16 ## [v0.9.10](https://github.com/dalance/procs/compare/v0.9.9...v0.9.10) - 2020-02-16 * [Added] cargo feature to build without docker dependencies [#41](https://github.com/dalance/procs/issues/41) * [Changed] remove unmaintained crates [#41](https://github.com/dalance/procs/issues/41) * [Fixed] garbage characters in watch mode ## [v0.9.9](https://github.com/dalance/procs/compare/v0.9.8...v0.9.9) - 2020-02-12 ## [v0.9.8](https://github.com/dalance/procs/compare/v0.9.7...v0.9.8) - 2020-02-12 ## [v0.9.7](https://github.com/dalance/procs/compare/v0.9.6...v0.9.7) - 2020-02-12 * [Added] widths of columns are adjusted over iteration in watch mode * [Fixed] suppress flicker in watch mode ## [v0.9.6](https://github.com/dalance/procs/compare/v0.9.5...v0.9.6) - 2020-02-05 * [Changed] --watch and --watch-interval option [#36](https://github.com/dalance/procs/issues/36) ## [v0.9.5](https://github.com/dalance/procs/compare/v0.9.4...v0.9.5) - 2020-01-30 * [Fixed] Remove --suid to fix security vulnerability (arbitrary command execution by root) [#38](https://github.com/dalance/procs/issues/38) ## [v0.9.4](https://github.com/dalance/procs/compare/v0.9.3...v0.9.4) - 2020-01-29 ## [v0.9.3](https://github.com/dalance/procs/compare/v0.9.2...v0.9.3) - 2020-01-29 * [Fixed] tree view with filter [#37](https://github.com/dalance/procs/issues/37) ## [v0.9.2](https://github.com/dalance/procs/compare/v0.9.1...v0.9.2) - 2020-01-26 * [Changed] update console to v0.9.2 [#34](https://github.com/dalance/procs/issues/34) * [Fixed] usage_mem overflow * [Fixed] Ctrl-C is ignored on Windows [#35](https://github.com/dalance/procs/issues/35) ## [v0.9.1](https://github.com/dalance/procs/compare/v0.9.0...v0.9.1) - 2020-01-24 * [Fixed] clear screen at entering watch mode ## [v0.9.0](https://github.com/dalance/procs/compare/v0.8.16...v0.9.0) - 2020-01-23 * [Added] sort order changing by keyboard [#31](https://github.com/dalance/procs/issues/31) * [Fixed] start_time slow down * [Changed] from failure to anyhow ## [v0.8.16](https://github.com/dalance/procs/compare/v0.8.15...v0.8.16) - 2019-12-09 * [Fixed] refine PPID == PID case ## [v0.8.15](https://github.com/dalance/procs/compare/v0.8.14...v0.8.15) - 2019-12-09 * [Fixed] Tree view failure caused by PPID == PID ## [v0.8.14](https://github.com/dalance/procs/compare/v0.8.13...v0.8.14) - 2019-11-18 * [Changed] update procfs to v0.7.1 ## [v0.8.13](https://github.com/dalance/procs/compare/v0.8.12...v0.8.13) - 2019-10-30 * [Changed] update procfs to v0.7.0 ## [v0.8.12](https://github.com/dalance/procs/compare/v0.8.11...v0.8.12) - 2019-10-21 * [Added] UidLogin/UserLogin column * [Changed] update procfs to v0.6.0 ## [v0.8.11](https://github.com/dalance/procs/compare/v0.8.10...v0.8.11) - 2019-10-08 * [Changed] update procfs to v0.5.4 ## [v0.8.10](https://github.com/dalance/procs/compare/v0.8.9...v0.8.10) - 2019-10-07 * [Changed] use libproc v0.5 ## [v0.8.9](https://github.com/dalance/procs/compare/v0.8.8...v0.8.9) - 2019-09-05 * [Added] max_width/min_width option ## [v0.8.8](https://github.com/dalance/procs/compare/v0.8.7...v0.8.8) - 2019-06-25 * [Fixed] SIGSEGV at parallel test caused by non-threadsafe function call of rust-users ## [v0.8.7](https://github.com/dalance/procs/compare/v0.8.6...v0.8.7) - 2019-06-18 * [Fixed] watch mode panic on Windows * [Changed] the crate to get executable from palaver to process_path * [Changed] remove build.rs ## [v0.8.6](https://github.com/dalance/procs/compare/v0.8.5...v0.8.6) - 2019-06-10 * [Fixed] compile failure on i686 ## [v0.8.5](https://github.com/dalance/procs/compare/v0.8.4...v0.8.5) - 2019-05-08 * [Fixed] usage_cpu calculation mistake when interval is larger than 1s. ## [v0.8.4](https://github.com/dalance/procs/compare/v0.8.3...v0.8.4) - 2019-05-07 * [Added] suid option * [Fixed] some characters remain over refresh in watch mode ## [v0.8.3](https://github.com/dalance/procs/compare/v0.8.2...v0.8.3) - 2019-05-03 * [Fixed] panic caused by --tree and --sort ## [v0.8.2](https://github.com/dalance/procs/compare/v0.8.1...v0.8.2) - 2019-04-30 * [Fixed] panic caused by procfs ## [v0.8.1](https://github.com/dalance/procs/compare/v0.8.0...v0.8.1) - 2019-04-03 * [Fixed] watch mode with search is broken ## [v0.8.0](https://github.com/dalance/procs/compare/v0.7.6...v0.8.0) - 2019-04-03 * [Added] tree view ## [v0.7.6](https://github.com/dalance/procs/compare/v0.7.5...v0.7.6) - 2019-03-22 * [Fixed] show process list on --config and --list [#15](https://github.com/dalance/procs/pull/15) ## [v0.7.5](https://github.com/dalance/procs/compare/v0.7.4...v0.7.5) - 2019-03-21 * [Changed] use OS-specific location for the configuration file [#14](https://github.com/dalance/procs/pull/14) ## [v0.7.4](https://github.com/dalance/procs/compare/v0.6.0...v0.7.4) - 2019-03-16 * [Added] windows support * [Changed] fast exit of watch mode ## [v0.6.0](https://github.com/dalance/procs/compare/v0.5.8...v0.6.0) - 2019-03-07 * [Added] watch mode * [Fixed] panic by truncate inside multi-byte unicode character ## [v0.5.8](https://github.com/dalance/procs/compare/v0.5.7...v0.5.8) - 2019-03-06 * [Added] column description to `--list` output * [Changed] sort indicator refine * [Fixed] wrong column width calculation about full-width characters * [Fixed] wrong `By*` style on center/right aligned column ## [v0.5.7](https://github.com/dalance/procs/compare/v0.5.6...v0.5.7) - 2019-03-05 * [Added] separator option to `~/.procs.toml` setting * [Added] `--list` option to show column kind list * [Added] Slot column to insert column by `--insert` oprion * [Added] Sort indicator * [Changed] the first decimal place of day/year in CpuTime is shown * [Changed] default separator from "|" to "│" ( U+2502:Box Drawings Light Vertical ) * [Changed] eip/esp/sig* format to 16 hex digits * [Changed] sort keyword is matched with column kind * [Fixed] unmatched `--sort*` affects sort order ## [v0.5.6](https://github.com/dalance/procs/compare/v0.5.5...v0.5.6) - 2019-03-01 * [Added] Ssb column * [Added] sort option ## [v0.5.5](https://github.com/dalance/procs/compare/v0.5.4...v0.5.5) - 2019-02-28 * [Added] logical operation for search keywords * [Changed] default logical operation for search keywords from OR to AND ## [v0.5.4](https://github.com/dalance/procs/compare/v0.5.3...v0.5.4) - 2019-02-27 * [Added] text align option ## [v0.5.3](https://github.com/dalance/procs/compare/v0.5.2...v0.5.3) - 2019-02-27 * [Fixed] panic by overflow ## [v0.5.2](https://github.com/dalance/procs/compare/v0.5.1...v0.5.2) - 2019-02-25 * [Fixed] `cargo install` failure on macOS ## [v0.5.1](https://github.com/dalance/procs/compare/v0.5.0...v0.5.1) - 2019-02-24 * [Fixed] CI issue ## [v0.5.0](https://github.com/dalance/procs/compare/v0.4.8...v0.5.0) - 2019-02-23 * [Added] macOS support * [Added] ContextSw/Gid*/Group*/Policy/Sig*/Uid*/User* column ## [v0.4.8](https://github.com/dalance/procs/compare/v0.4.7...v0.4.8) - 2019-02-21 * [Added] `color_mode` option to `~/.procs.toml` setting * [Added] `--pager` commandline option * [Fixed] pager command of `~/.procs.toml` is not affected ## [v0.4.7](https://github.com/dalance/procs/compare/v0.4.6...v0.4.7) - 2019-02-18 * [Fixed] panic caused by zombie process * [Fixed] build failure on Rust 1.31.1 ## [v0.4.6](https://github.com/dalance/procs/compare/v0.4.5...v0.4.6) - 2019-02-16 * [Fixed] default pager option is not affected ## [v0.4.5](https://github.com/dalance/procs/compare/v0.4.4...v0.4.5) - 2019-02-14 * [Added] Vm*/Wchan column * [Changed] `VmPeak` is added to default ## [v0.4.4](https://github.com/dalance/procs/compare/v0.4.3...v0.4.4) - 2019-02-11 * [Added] `cut_to_*` options to `~/.procs.toml` setting * [Changed] default pager is changed to `less -SR` ## [v0.4.3](https://github.com/dalance/procs/compare/v0.4.2...v0.4.3) - 2019-02-07 * [Added] Eip/Esp/MajFlt/MinFlt/Nice/Ppid/Priority/Processor/RtPriority column ## [v0.4.2](https://github.com/dalance/procs/compare/v0.4.1...v0.4.2) - 2019-02-06 * [Changed] default pager is changed to `less` ## [v0.4.1](https://github.com/dalance/procs/compare/v0.4.0...v0.4.1) - 2019-02-06 * [Fixed] failure of text width calculation with tab character ## [v0.4.0](https://github.com/dalance/procs/compare/v0.3.5...v0.4.0) - 2019-02-06 * [Added] pager support * [Fixed] pipe broken error procs-0.14.9/Cargo.lock0000644000002116550000000000100102420ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", "version_check", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-stream" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", "pin-project-lite", ] [[package]] name = "async-stream-impl" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "async-trait" version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-targets 0.52.6", ] [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bindgen" version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", "lazycell", "log", "peeking_take_while", "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn 2.0.96", "which 4.4.2", ] [[package]] name = "bindgen" version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ "bitflags 2.8.0", "cexpr", "clang-sys", "itertools", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn 2.0.96", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "borsh" version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb65153674e51d3a42c8f27b05b9508cea85edfaade8aa46bc8fc18cecdfef3" dependencies = [ "borsh-derive", "cfg_aliases", ] [[package]] name = "borsh-derive" version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a396e17ad94059c650db3d253bb6e25927f1eb462eede7e7a153bb6e75dce0a7" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "bsd-kvm" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b4eb28b17b77a2974f6307a6f7f18c294d71543ceac0f021b89a4eb9e3ccbe" dependencies = [ "bsd-kvm-sys", "libc", "thiserror 1.0.69", ] [[package]] name = "bsd-kvm-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65408f926d3766661595309e0a70bbed02ef27bb74603db6199ab9394103c932" dependencies = [ "bindgen 0.65.1", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-unit" version = "5.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" dependencies = [ "rust_decimal", "serde", "utf8-width", ] [[package]] name = "bytecheck" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ "bytecheck_derive", "ptr_meta", "simdutf8", ] [[package]] name = "bytecheck_derive" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ "shlex", ] [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "windows-targets 0.52.6", ] [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "clap" version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_complete" version = "4.5.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" dependencies = [ "clap", ] [[package]] name = "clap_derive" version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck", "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "clap_lex" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", "libc", "once_cell", "unicode-width 0.2.0", "windows-sys 0.59.0", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crc32fast" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ "bitflags 2.8.0", "crossterm_winapi", "libc", "mio 0.8.11", "parking_lot", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags 2.8.0", "crossterm_winapi", "mio 1.0.3", "parking_lot", "rustix", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] [[package]] name = "directories" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ "dirs-sys 0.5.0", ] [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys 0.4.1", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users 0.4.6", "windows-sys 0.48.0", ] [[package]] name = "dirs-sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users 0.5.0", "windows-sys 0.59.0", ] [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "dockworker" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b4515d004ea0f740bdcae249ee555fa4a8687e9af881ed68812144a0acb2dbf" dependencies = [ "async-stream", "async-trait", "base64", "byteorder", "bytes", "chrono", "dirs", "futures", "http", "hyper", "hyperlocal", "log", "named_pipe", "nix 0.26.4", "serde", "serde_json", "tar", "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-util", "url", ] [[package]] name = "downcast" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encode_unicode" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_home" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", "winapi", ] [[package]] name = "errno" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "errno-dragonfly" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ "cc", "libc", ] [[package]] name = "filetime" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", "libredox", "windows-sys 0.59.0", ] [[package]] name = "flate2" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fragile" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "futures-sink" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "getch" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13990e2d5b29e1770ddf7fc000afead4acb9bd8f8a9602de63bf189e261b1ba8" dependencies = [ "libc", "termios", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "home" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "http" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "http-body" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", "pin-project-lite", ] [[package]] name = "httparse" version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", "socket2", "tokio", "tower-service", "tracing", "want", ] [[package]] name = "hyperlocal" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c" dependencies = [ "futures-util", "hex", "hyper", "pin-project", "tokio", ] [[package]] name = "iana-time-zone" version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "idna" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", ] [[package]] name = "libproc" version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78a09b56be5adbcad5aa1197371688dc6bb249a26da3bca2011ee2fb987ebfb" dependencies = [ "bindgen 0.70.1", "errno 0.3.10", "libc", ] [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.8.0", "libc", "redox_syscall", ] [[package]] name = "linux-raw-sys" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] [[package]] name = "minus" version = "5.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "093bd0520d2a37943566a73750e6d44094dac75d66a978d1f0d97ffc78686832" dependencies = [ "crossbeam-channel", "crossterm 0.27.0", "once_cell", "parking_lot", "regex", "textwrap", "thiserror 1.0.69", ] [[package]] name = "mio" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", "windows-sys 0.48.0", ] [[package]] name = "mio" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", "wasi", "windows-sys 0.52.0", ] [[package]] name = "mockall" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" dependencies = [ "cfg-if", "downcast", "fragile", "mockall_derive", "predicates", "predicates-tree", ] [[package]] name = "mockall_derive" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" dependencies = [ "cfg-if", "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "named_pipe" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad9c443cce91fc3e12f017290db75dde490d685cdaaf508d7159d7cf41f0eb2b" dependencies = [ "winapi", ] [[package]] name = "nix" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", "memoffset", "pin-utils", ] [[package]] name = "nix" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.8.0", "cfg-if", "cfg_aliases", "libc", ] [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_threads" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] [[package]] name = "object" version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" dependencies = [ "parking_lot_core", ] [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "pager" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2599211a5c97fbbb1061d3dc751fa15f404927e4846e07c643287d6d1f462880" dependencies = [ "errno 0.2.8", "libc", ] [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.52.6", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] [[package]] name = "predicates" version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "predicates-core", ] [[package]] name = "predicates-core" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", ] [[package]] name = "prettyplease" version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", "syn 2.0.96", ] [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "procfs" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ "bitflags 2.8.0", "chrono", "flate2", "hex", "procfs-core", "rustix", ] [[package]] name = "procfs-core" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags 2.8.0", "chrono", "hex", ] [[package]] name = "procs" version = "0.14.9" dependencies = [ "anyhow", "bsd-kvm", "bsd-kvm-sys", "byte-unit", "chrono", "clap", "clap_complete", "console", "directories", "dockworker", "errno 0.3.10", "getch", "libc", "libproc", "minus", "nix 0.29.0", "once_cell", "pager", "procfs", "regex", "serde", "serde_derive", "termbg", "tokio", "toml", "unicode-width 0.2.0", "uzers", "which 7.0.1", "windows-sys 0.59.0", ] [[package]] name = "ptr_meta" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.8.0", ] [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", "thiserror 1.0.69", ] [[package]] name = "redox_users" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom", "libredox", "thiserror 2.0.11", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rend" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ "bytecheck", ] [[package]] name = "rkyv" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", "bytes", "hashbrown 0.12.3", "ptr_meta", "rend", "rkyv_derive", "seahash", "tinyvec", "uuid", ] [[package]] name = "rkyv_derive" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "rust_decimal" version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "borsh", "bytes", "num-traits", "rand", "rkyv", "serde", "serde_json", ] [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags 2.8.0", "errno 0.3.10", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] [[package]] name = "rustversion" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "serde" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "serde_json" version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio 0.8.11", "mio 1.0.3", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "simdutf8" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simplelog" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" dependencies = [ "log", "termcolor", "time", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", "xattr", ] [[package]] name = "termbg" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf44577a1adf3dfd7fec3b8763074467e27b2ad35ff9157bc3f0a51bb0a3dd4" dependencies = [ "crossterm 0.28.1", "log", "mockall", "scopeguard", "simplelog", "thiserror 2.0.11", "winapi", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "termios" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" dependencies = [ "libc", ] [[package]] name = "termtree" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "textwrap" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "unicode-width 0.1.14", ] [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ "thiserror-impl 2.0.11", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "thiserror-impl" version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "time" version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", "libc", "num-conv", "num_threads", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tinyvec" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", "libc", "mio 1.0.3", "pin-project-lite", "socket2", "tokio-macros", "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "tokio-stream" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", "tokio", ] [[package]] name = "tokio-util" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", ] [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tower-service" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "url" version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" [[package]] name = "uzers" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4df81ff504e7d82ad53e95ed1ad5b72103c11253f39238bcc0235b90768a97dd" dependencies = [ "libc", "log", ] [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ "try-lock", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn 2.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "which" version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", "home", "once_cell", "rustix", ] [[package]] name = "which" version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a9e33648339dc1642b0e36e21b3385e6148e289226f657c809dee59df5028" dependencies = [ "either", "env_home", "rustix", "winsafe", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "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_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[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_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] [[package]] name = "winsafe" version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wyz" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] [[package]] name = "xattr" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" dependencies = [ "libc", "linux-raw-sys", "rustix", ] [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", "synstructure", ] [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] [[package]] name = "zerofrom" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", "synstructure", ] [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] procs-0.14.9/Cargo.toml0000644000000116260000000000100102610ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.74" name = "procs" version = "0.14.9" authors = ["dalance@gmail.com"] build = false exclude = [ "img/*", "config/*", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "A modern replacement for ps" readme = "README.md" keywords = ["process"] categories = ["command-line-utilities"] license = "MIT" repository = "https://github.com/dalance/procs" [package.metadata.release] pre-release-commit-message = "Prepare to v{{version}}" tag-message = "Bump version to {{version}}" tag-prefix = "" [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" replace = "v{{version}}" search = "Unreleased" [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" replace = "{{date}}" search = "ReleaseDate" [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" replace = """ Change Log ## [Unreleased](https://github.com/dalance/procs/compare/v{{version}}...Unreleased) - ReleaseDate""" search = "Change Log" [[package.metadata.release.pre-release-replacements]] file = "README.md" replace = "changelog-v{{version}}" search = 'changelog-v[0-9\.]+' [[package.metadata.release.pre-release-replacements]] file = "README.md" replace = "v{{version}}/procs-{{version}}" search = 'v[0-9\.]+/procs-[0-9\.]+' [[package.metadata.release.pre-release-replacements]] file = "snapcraft.yaml" replace = "version v{{version}}" search = 'version v[0-9\.]+' [package.metadata.rpm.cargo] buildflags = ["--release"] target = "x86_64-unknown-linux-musl" [package.metadata.rpm.targets.procs] path = "/usr/bin/procs" [profile.release] lto = true codegen-units = 1 [[bin]] name = "procs" path = "src/main.rs" [dependencies.anyhow] version = "1.0" [dependencies.byte-unit] version = "5.1" [dependencies.chrono] version = "0.4.39" features = ["clock"] default-features = false [dependencies.clap] version = "4.4" features = ["derive"] [dependencies.clap_complete] version = "4.4" [dependencies.console] version = "0.15.10" [dependencies.directories] version = "6.0.0" [dependencies.dockworker] version = "0.5.1" optional = true [dependencies.getch] version = "0.3.1" [dependencies.libc] version = "0.2" [dependencies.minus] version = "5.6" features = [ "static_output", "search", ] [dependencies.once_cell] version = "1.20.2" [dependencies.serde] version = "1.0" [dependencies.serde_derive] version = "1.0" [dependencies.termbg] version = "0.6.2" [dependencies.tokio] version = "1.43" features = ["rt"] optional = true [dependencies.toml] version = "0.8" [dependencies.unicode-width] version = "0.2" [features] default = ["docker"] docker = [ "dockworker", "tokio", ] [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.pager] version = "0.16.1" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.procfs] version = "0.17.0" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.regex] version = "1.11" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.uzers] version = "0.12" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.which] version = "7" [target.'cfg(target_os = "freebsd")'.dependencies.bsd-kvm] version = "0.1.5" [target.'cfg(target_os = "freebsd")'.dependencies.bsd-kvm-sys] version = "0.2.0" [target.'cfg(target_os = "freebsd")'.dependencies.pager] version = "0.16.1" [target.'cfg(target_os = "freebsd")'.dependencies.uzers] version = "0.12" [target.'cfg(target_os = "freebsd")'.dependencies.which] version = "7" [target.'cfg(target_os = "macos")'.dependencies.errno] version = "0.3" [target.'cfg(target_os = "macos")'.dependencies.libproc] version = "0.14" [target.'cfg(target_os = "macos")'.dependencies.nix] version = "0.29.0" features = ["process"] [target.'cfg(target_os = "macos")'.dependencies.pager] version = "0.16" [target.'cfg(target_os = "macos")'.dependencies.uzers] version = "0.12" [target.'cfg(target_os = "macos")'.dependencies.which] version = "7" [target.'cfg(target_os = "windows")'.dependencies.windows-sys] version = "0.59" features = [ "Win32_Foundation", "Win32_Networking_WinSock", "Win32_NetworkManagement_IpHelper", "Win32_Security", "Win32_System_Diagnostics_ToolHelp", "Win32_System_ProcessStatus", "Win32_System_Threading", ] [badges.codecov] branch = "master" repository = "dalance/procs" service = "github" [badges.travis-ci] repository = "dalance/procs" procs-0.14.9/Cargo.toml.orig000064400000000000000000000060411046102023000137350ustar 00000000000000[package] name = "procs" version = "0.14.9" authors = ["dalance@gmail.com"] repository = "https://github.com/dalance/procs" keywords = ["process"] categories = ["command-line-utilities"] license = "MIT" readme = "README.md" description = "A modern replacement for ps" edition = "2021" exclude = ["img/*", "config/*"] rust-version = "1.74" [package.metadata.release] pre-release-commit-message = "Prepare to v{{version}}" tag-message = "Bump version to {{version}}" tag-prefix = "" pre-release-replacements = [ {file="CHANGELOG.md", search="Unreleased", replace="v{{version}}"}, {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}"}, {file="CHANGELOG.md", search="Change Log", replace="Change Log\n\n## [Unreleased](https://github.com/dalance/procs/compare/v{{version}}...Unreleased) - ReleaseDate"}, {file="README.md", search = "changelog-v[0-9\\.]+", replace = "changelog-v{{version}}" }, {file="README.md", search = "v[0-9\\.]+/procs-[0-9\\.]+", replace = "v{{version}}/procs-{{version}}" }, {file="snapcraft.yaml", search="version v[0-9\\.]+", replace="version v{{version}}"}, ] [features] default = ["docker"] docker = ["dockworker", "tokio"] [badges] travis-ci = { repository = "dalance/procs" } codecov = { repository = "dalance/procs", branch = "master", service = "github" } [dependencies] anyhow = "1.0" byte-unit = "5.1" clap = {version = "4.4", features = ["derive"]} clap_complete = "4.4" console = "0.15.10" chrono = {version = "0.4.39", default-features = false, features = ["clock"]} directories = "6.0.0" dockworker = { version = "0.5.1", optional = true } getch = "0.3.1" libc = "0.2" minus = { version = "5.6", features = ["static_output", "search"] } once_cell = "1.20.2" serde = "1.0" serde_derive = "1.0" termbg = "0.6.2" tokio = { version = "1.43", optional = true, features = ["rt"] } toml = "0.8" unicode-width = "0.2" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] pager = "0.16.1" procfs = "0.17.0" regex = "1.11" uzers = "0.12" which = "7" [target.'cfg(target_os = "macos")'.dependencies] libproc = "0.14" nix = {version = "0.29.0", features = ["process"]} errno = "0.3" pager = "0.16" uzers = "0.12" which = "7" [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_NetworkManagement_IpHelper", "Win32_Security", "Win32_System_Diagnostics_ToolHelp", "Win32_System_ProcessStatus", "Win32_System_Threading"] } [target.'cfg(target_os = "freebsd")'.dependencies] bsd-kvm = "0.1.5" bsd-kvm-sys = "0.2.0" pager = "0.16.1" uzers = "0.12" which = "7" [package.metadata.rpm.cargo] buildflags = ["--release"] target = "x86_64-unknown-linux-musl" [package.metadata.rpm.targets] procs = { path = "/usr/bin/procs" } [profile.release] lto = true codegen-units = 1 procs-0.14.9/LICENSE000064400000000000000000000020411046102023000120470ustar 00000000000000MIT License Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. procs-0.14.9/Makefile000064400000000000000000000025011046102023000125030ustar 00000000000000VERSION = $(patsubst "%",%, $(word 3, $(shell grep version Cargo.toml))) BUILD_TIME = $(shell date +"%Y/%m/%d %H:%M:%S") GIT_REVISION = $(shell git log -1 --format="%h") RUST_VERSION = $(word 2, $(shell rustc -V)) LONG_VERSION = "$(VERSION) ( rev: $(GIT_REVISION), rustc: $(RUST_VERSION), build at: $(BUILD_TIME) )" BIN_NAME = procs export LONG_VERSION .PHONY: all test clean release_lnx release_win release_mac all: test test: cargo test --locked watch: cargo watch test --locked clean: cargo clean release_lnx: cargo build --locked --release --target=x86_64-unknown-linux-musl zip -j ${BIN_NAME}-v${VERSION}-x86_64-linux.zip target/x86_64-unknown-linux-musl/release/${BIN_NAME} release_win: cargo build --locked --release --target=x86_64-pc-windows-msvc mv -v target/x86_64-pc-windows-msvc/release/${BIN_NAME}.exe ./ 7z a ${BIN_NAME}-v${VERSION}-x86_64-windows.zip ${BIN_NAME}.exe release_mac: cargo build --locked --release --target=x86_64-apple-darwin cargo build --locked --release --target=aarch64-apple-darwin zip -j ${BIN_NAME}-v${VERSION}-x86_64-mac.zip target/x86_64-apple-darwin/release/${BIN_NAME} zip -j ${BIN_NAME}-v${VERSION}-aarch64-mac.zip target/aarch64-apple-darwin/release/${BIN_NAME} release_rpm: mkdir -p target cargo rpm build cp target/x86_64-unknown-linux-musl/release/rpmbuild/RPMS/x86_64/* ./ procs-0.14.9/README.md000064400000000000000000001001331046102023000123220ustar 00000000000000# procs **procs** is a replacement for `ps` written in [Rust](https://www.rust-lang.org/). [![Actions Status](https://github.com/dalance/procs/workflows/Regression/badge.svg)](https://github.com/dalance/procs/actions) [![Changelog](https://img.shields.io/badge/changelog-v0.14.9-green.svg)](https://github.com/dalance/procs/blob/master/CHANGELOG.md) [![Crates.io](https://img.shields.io/crates/v/procs.svg)](https://crates.io/crates/procs) [![procs](https://snapcraft.io/procs/badge.svg)](https://snapcraft.io/procs) [![homebrew](https://img.shields.io/homebrew/v/procs.svg)](https://formulae.brew.sh/formula/procs) ## Documentation quick links * [Features](#features) * [Platform](#platform) * [Installation](#installation) * [Usage](#usage) * [Configuration](#configuration) ## Features - Colored and human-readable output - Automatic theme detection based on terminal background - Multi-column keyword search - Some additional information which are not supported by `ps` - TCP/UDP port - Read/Write throughput - Docker container name - More memory information - Pager support - Watch mode (like `top`) - Tree view ## Platform - Linux is supported. - macOS is experimentally supported. - macOS version is checked on GitHub Actions environment only. - The issues caused by real-machine are welcome. - Windows is supported. - FreeBSD is experimentally supported. ## Installation ### Download binary Download from [release page](https://github.com/dalance/procs/releases/latest), and extract to the directory in PATH. ### [![Packaging status](https://repology.org/badge/vertical-allrepos/procs.svg?columns=3)](https://repology.org/project/procs/versions) ### Nixpkgs You can install from [Nixpkgs](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/admin/procs/default.nix). ``` nix-env --install procs ``` ### snapcraft You can install from [snapcraft](https://snapcraft.io/procs). ``` sudo snap install procs ``` ### homebrew You can install from [homebrew](https://formulae.brew.sh/formula/procs). ``` brew install procs ``` ### MacPorts You can install from [MacPorts](https://ports.macports.org/port/procs/). ``` sudo port install procs ``` ### Alpine Linux You can install from the [Alpine Linux repository](https://pkgs.alpinelinux.org/packages?name=procs). The correct repository (see above link for the most up-to-date information) should be enabled before `apk add`. ``` sudo apk add procs ``` ### Arch Linux You can install from the [Arch Linux extra repository](https://archlinux.org/packages/extra/x86_64/procs/). ``` sudo pacman -S procs ``` ### Scoop You can install with [scoop](https://scoop.sh/). ``` scoop install procs ``` ### Fedora ``` sudo dnf install procs ``` ### Windows ``` winget install procs ``` ### RPM You can install with rpm. ``` sudo rpm -i https://github.com/dalance/procs/releases/download/v0.14.9/procs-0.14.9-1.x86_64.rpm ``` ### Cargo You can install with [cargo](https://crates.io/crates/procs). ``` cargo install procs ``` ### X-CMD You can install with [x-cmd](https://www.x-cmd.com). ``` x env use procs # or x procs # Download procs, and invoke procs in a way that does not affect the current environment ``` ## Installation Notes ### Permissions issues On macOS, normal users can't access any information on other users' processes. On Linux, normal users can't access some information (ex. Read/Write throughput) of other users. If you want to show this information, you should use `sudo`. ```console $ sudo procs [sudo] password for ...: ``` If you want to skip password input, you can add the following entry to `/etc/sudoers`. ```text [user or group] ALL= NOPASSWD: [procs binary path] // ex. myuser ALL= NOPASSWD: /usr/local/bin/procs ``` ## Usage In the following screenshots, `config/large.toml` is used as the configuration. ### Show all processes Type `procs` only. It shows the information of all processes. ```console procs ``` ![procs](https://user-images.githubusercontent.com/4331004/55446625-5e5fce00-55fb-11e9-8914-69e8640d89d7.png) ### Search by non-numeric keyword If you add any keyword as argument, it is matched to `USER`, `Command` by default. ```console procs zsh ``` If you want to add columns matching to non-numeric keyword, `nonnumeric_search` option can be used in configuration file. ![procs_zsh](https://user-images.githubusercontent.com/4331004/55446648-71729e00-55fb-11e9-8e12-1ca63911c568.png) ### Search by numeric keyword If a numeric is used as the keyword, it is matched to `PID` by default. Numeric is treated as exact match, and non-numeric is treated as partial match by default. ```console procs --or 6000 60000 60001 16723 ``` If you want to add columns matching to numeric keyword, `numeric_search` option can be used in configuration file. ![procs_port](https://user-images.githubusercontent.com/4331004/55446667-83ecd780-55fb-11e9-8959-53209837c4ee.png) Note that procfs permissions only allow identifying listening ports for processes owned by the current user, so not all ports will show up unless run as root. ### Logical operation of search keywords If there are some keywords, logical operation between the keywords can be specified by commandline option. - `--and` : The processes that match with all keywords are shown. - `--or` : The processes that match with any keyword are shown. - `--nand`: The processes are shown unless these match with all keywords. - `--nor` : The processes are shown unless these match with any keyword. The default operation can be specified in the [configuration file](#configuration). See `[search]` section. ### Show Docker container name If you have access permission to docker daemon ( `unix:///var/run/docker.sock` ), `Docker` column is added. ```console procs growi ``` ![procs_docker](https://user-images.githubusercontent.com/4331004/55446681-91a25d00-55fb-11e9-943d-5b5caeb23c62.png) Note that procs gets the container information through UNIX domain socket, so [Docker Toolbox](https://docs.docker.com/toolbox/) on macOS (doesn't use UNIX domain socket) is not supported. [Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/) is supported but not tested. ### Pager If output lines exceed terminal height, pager is used automatically. This behavior and pager command can be specified by [configuration file](#pager-section). #### Linux / macOS On Linux and macOS, `less` is the default pager. If there is not `less`, `more` is used. Instead of them, built-in pager can be used by configuration `use_builtin`. #### Windows On Windows, built-in pager is always used. ### Watch mode If `--watch` or `--watch-interval ` option is used, procs automatically updates output like `top`. If `--watch` is used, the update interval becomes 1s. The update interval can be specified by the argument of `--watch-interval`. There are some keyboard shortcuts to control. - `n`: Change the sort column to the next column - `p`: Change the sort column to the previous column - `a`: Change the sort order to ascending - `d`: Change the sort order to descending - `q`: Quit ### Tree view If `--tree` option is used, processes are sorted by dependency order and dependency tree is shown at left side. ```console procs --tree ``` ![procs_tree](https://user-images.githubusercontent.com/4331004/55446692-9ff07900-55fb-11e9-8b66-a8432df0a8e1.png) If `TreeSlot` column exists in config, dependency tree is shown at the slot. ### Sort column Column sort order can be changed by `--sorta` or `--sortd` option. The last character of `--sorta` and `--sortd` means sort order: "a"scending and "d"escending. The column for sort is selected by the option keyword. The keyword is matched with column kind that is shown by `--list` option. If `--sorta cputime`, column is sorted by `CpuTime` with ascending order. If `--sortd rss`, column is sorted by `VmRss` with descending order. The keyword is matched partially and case is ignored. The default sort is specified by `[sort]` section in the [configuration file](#configuration). ```console procs --sortd cpu ``` ![procs_sort](https://user-images.githubusercontent.com/4331004/55446704-ab43a480-55fb-11e9-81dc-e3ac1a1e2507.png) ### Insert column `--insert` option inserts new column to the position of `Slot` column or `MultiSlot` column. The column for insert is selected by the option keyword. The keyword is the same as sort option. A `Slot` column can be used by an inserted column. If many insertions are required, many `Slot` columns should be added. A `MultiSlot` column can be used by many inserted columns. If there is a `MultiSlot`, all the remaining columns are inserted to the `MultiSlot`, and the subsequent `Slot` / `MultiSlot` is not used. Unused `Slot` / `MultiSlot` is not shown. ### Shell completion `--gen-completion` option generates shell completion files under the current directory. The following shells are supported. * `zsh` * `bash` * `fish` * `powershell` * `elvish` `--gen-completion-out` option generates shell completion to stdout. You can source it directly on some shells. ```console source <(procs --gen-completion-out bash) ``` ## Configuration ### Configuration path You can change configuration by writing a configuration file. There are some configuration examples in `config` directory of this repository. `config/large.toml` is the default configuration before procs v0.9.21. The locations of the configuration file is OS-specific: * Linux: `~/.config/procs/config.toml`, `/etc/procs/procs.toml` * macOS: `~/Library/Preferences/com.github.dalance.procs/config.toml`, `/etc/procs/procs.toml` * Windows: `~/AppData/Roaming/dalance/procs/config/config.toml` For compatibility, if `~/.procs.toml` exists, it will be preferred to the OS-specific locations. ### Specify a configuration from command line `--use-config` option can specify a built-in configuration. `--load-config` option can specify a configuration file path. ### Configuration example The complete example of a configuration file can be generated by `--gen-config` option. ```toml [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false [[columns]] kind = "Username" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Right" [style] header = "BrightWhite|Black" unit = "BrightWhite|Black" tree = "BrightWhite|Black" [style.by_percentage] color_000 = "BrightBlue|Blue" color_025 = "BrightGreen|Green" color_050 = "BrightYellow|Yellow" color_075 = "BrightRed|Red" color_100 = "BrightRed|Red" [style.by_state] color_d = "BrightRed|Red" color_r = "BrightGreen|Green" color_s = "BrightBlue|Blue" color_t = "BrightCyan|Cyan" color_z = "BrightMagenta|Magenta" color_x = "BrightMagenta|Magenta" color_k = "BrightYellow|Yellow" color_w = "BrightYellow|Yellow" color_p = "BrightYellow|Yellow" [style.by_unit] color_k = "BrightBlue|Blue" color_m = "BrightGreen|Green" color_g = "BrightYellow|Yellow" color_t = "BrightRed|Red" color_p = "BrightRed|Red" color_x = "BrightBlue|Blue" [search] numeric_search = "Exact" nonnumeric_search = "Partial" logic = "And" [display] show_self = false show_thread = false show_thread_in_tree = true cut_to_terminal = true cut_to_pager = false cut_to_pipe = false color_mode = "Auto" [sort] column = 0 order = "Ascending" [docker] path = "unix:///var/run/docker.sock" [pager] mode = "Auto" ``` ### `[[columns]]` section `[[columns]]` section defines which columns are used. The first `[[columns]]` is shown at left side, and the last is shown at right side. | Key | Value | Default | Description | | ----------------- | ------------------- | ------- | ----------------------------------------------------------- | | kind | See `kind` list | | Column type | | style | See `style` list | | Column style | | numeric_search | true, false | false | Whether the column can be matched with numeric keywords | | nonnumeric_search | true, false | false | Whether the column can be matched with non-numeric keywords | | align | Left, Right, Center | Left | Text alignment | | max_width | [Number] | | Maximum column width | | min_width | [Number] | | Minimum column width | | header | [String] | | Alternate header description | #### `kind` list | procs `kind` | `ps` STANDARD FORMAT | Description | Linux | macOS | Windows | FreeBSD | | ------------ | --------------------- | --------------------------------------------- | ----- | ----- | ------- | ------- | | Ccgroup | -not supported- | Control group by compressed format | o | | | | | Cgroup | cgroup | Control group | o | | | | | Command | args | Command with all arguments | o | o | o | o | | ContextSw | -not supported- | Context switch count | o | o | | o | | CpuTime | cputime | Cumulative CPU time | o | o | o | o | | Docker | -not supported- | Docker container name | o | o | | | | Eip | eip | Instruction pointer | o | | | | | ElapsedTime | -not supported- | Elapsed time | o | o | o | o | | Env | `e` output modifier | Environment variables | o | | | o | | Esp | esp | Stack pointer | o | | | | | FileName | comm | File name | o | | | o | | Gid | egid | Group ID | o | o | o | o | | GidFs | fgid | File system group ID | o | | | | | GidReal | rgid | Real group ID | o | o | | o | | GidSaved | sgid | Saved group ID | o | o | | o | | Group | egroup | Group name | o | o | o | o | | GroupFs | fgroup | File system group name | o | | | | | GroupReal | rgroup | Real group name | o | o | | o | | GroupSaved | sgroup | Saved group name | o | o | | o | | MajFlt | maj_flt | Major page fault count | o | o | o | o | | MinFlt | min_flt | Minor page fault count | o | o | | o | | MultiSlot | -not supported- | Slot for `--insert` option | o | o | o | o | | Nice | ni | Nice value | o | o | | o | | Pgid | pgid | Process group ID | o | o | | o | | Pid | pid | Process ID ( or Thread ID sorrunded by `[]` ) | o | o | o | o | | Policy | policy | Scheduling policy | o | o | | | | Ppid | ppid | Parent process ID | o | o | o | o | | Priority | pri | Priority | o | o | o | o | | Processor | psr | Currently assigned processor | o | | | o | | ReadBytes | -not supported- | Read bytes from storage | o | o | o | o | | RtPriority | rtprio | Real-time priority | o | | | | | SecContext | label | Security context | o | | | | | Separator | -not supported- | Show `\|` for column separation | o | o | o | o | | Session | sid | Session ID | o | o | | o | | ShdPnd | pending | Pending signal mask for process | o | | | o | | SigBlk | blocked | Blocked signal mask | o | | | o | | SigCgt | caught | Caught signal mask | o | | | o | | SigIgn | ignored | Ignored signal mask | o | | | o | | SigPnd | pending | Pending signal mask for thread | o | | | | | Slot | -not supported- | Slot for `--insert` option | o | o | o | o | | Ssb | -not supported- | Speculative store bypass status | o | | | | | StartTime | start_time | Starting time | o | o | o | o | | State | s | Process state | o | o | | o | | TcpPort | -not supported- | Bound TCP ports | o | o | | | | Threads | nlwp | Thread count | o | o | | o | | TreeSlot | -not supported- | Slot for tree column | o | o | o | o | | Tty | tty | Controlling TTY | o | o | | o | | UdpPort | -not supported- | Bound UDP ports | o | o | | | | Uid | euid | User ID | o | o | o | o | | UidFs | fuid | File system user ID | o | | | | | UidLogin | -not supported- | Login user ID | o | | | | | UidReal | ruid | Real user ID | o | o | | o | | UidSaved | suid | Saved user ID | o | o | | o | | UsageCpu | %cpu | CPU utilization | o | o | o | o | | UsageMem | %mem | Memory utilization | o | o | o | o | | User | euser | User name | o | o | o | o | | UserFs | fuser | File system user name | o | | | | | UserLogin | -not supported- | Login user name | o | | | | | UserReal | ruser | Real user name | o | o | | o | | UserSaved | suser | Saved user name | o | o | | o | | VmData | -not supported- | Data size | o | | | o | | VmExe | trs | Text segments size | o | | | o | | VmHwm | -not supported- | Peak resident set size | o | | o | o | | VmLib | -not supported- | Library code size | o | | | | | VmLock | -not supported- | Locked memory size | o | | | | | VmPeak | -not supported- | Peak virtual memory size | o | | o | | | VmPin | -not supported- | Pinned memory size | o | | o | | | VmPte | -not supported- | Page table entries size | o | | | | | VmRss | rss | Resident set size | o | o | o | o | | VmSize | vsz | Physical page size | o | o | o | o | | VmStack | -not supported- | Stack size | o | | | o | | VmSwap | -not supported- | Swapped-out virtual memory size | o | | o | | | Wchan | wchan | Process sleeping kernel function | o | | | o | | WorkDir | -not supported- | Current working directory | o | | | | | WriteByte | -not supported- | Write bytes to storage | o | o | o | o | #### `style` list - BrightBlack - BrightRed - BrightGreen - BrightYellow - BrightBlue - BrightMagenta - BrightCyan - BrightWhite - Black - Red - Green - Yellow - Blue - Magenta - Cyan - White - Color256 - ByPercentage - ByState - ByUnit There are some special styles like `ByPercentage`, `ByState`, `ByUnit`. These are the styles for value-aware coloring. For example, if `ByUnit` is chosen, color can be specified for each unit of value ( like `K`, `M`, `G`,,, ). The colors can be configured in `[style.by_unit]` section. Other colors can be configured as the same as `color`. ### `[style]` section `[style]` section defines colors of header, unit and each styles. The available list of color is below. | Subsection | Key | Value | Default | Description | | ------------- | --------- | ---------------- | ---------------------- | -------------------- | | | header | See `color` list | BrightWhite\|Black | Header color | | | unit | See `color` list | BrightWhite\|Black | Unit color | | | tree | See `color` list | BrightWhite\|Black | Tree color | | by_percentage | color_000 | See `color` list | BrightBlue\|Blue | Color at 0% - 25% | | by_percentage | color_025 | See `color` list | BrightGreen\|Green | Color at 25% - 50% | | by_percentage | color_050 | See `color` list | BrightYellow\|Yellow | Color at 50% - 75% | | by_percentage | color_075 | See `color` list | BrightRed\|Red | Color at 75% - 100% | | by_percentage | color_100 | See `color` list | BrightRed\|Red | Color at 100% - | | by_state | color_d | See `color` list | BrightRed\|Red | Color at `D` state | | by_state | color_r | See `color` list | BrightGreen\|Green | Color at `R` state | | by_state | color_s | See `color` list | BrightBlue\|Blue | Color at `S` state | | by_state | color_t | See `color` list | BrightCyan\|Cyan | Color at `T` state | | by_state | color_z | See `color` list | BrightMagenta\|Magenta | Color at `Z` state | | by_state | color_x | See `color` list | BrightMagenta\|Magenta | Color at `X` state | | by_state | color_k | See `color` list | BrightYellow\|Yellow | Color at `K` state | | by_state | color_w | See `color` list | BrightYellow\|Yellow | Color at `W` state | | by_state | color_p | See `color` list | BrightYellow\|Yellow | Color at `P` state | | by_unit | color_k | See `color` list | BrightBlue\|Blue | Color at unit `K` | | by_unit | color_m | See `color` list | BrightGreen\|Green | Color at unit `M` | | by_unit | color_g | See `color` list | BrightYellow\|Yellow | Color at unit `G` | | by_unit | color_t | See `color` list | BrightRed\|Red | Color at unit `T` | | by_unit | color_p | See `color` list | BrightRed\|Red | Color at unit `P` | | by_unit | color_x | See `color` list | BrightBlue\|Blue | Color at other unit | #### `color` list - BrightBlack - BrightRed - BrightGreen - BrightYellow - BrightBlue - BrightMagenta - BrightCyan - BrightWhite - Black - Red - Green - Yellow - Blue - Magenta - Cyan - White - Color256 Colors can be configured by theme through `|`. ```toml style = "BrightWhite|Black" # BrightWhite for dark theme and Black for light theme style = "BrightWhite" # BrightWhite for both theme ``` The first color is for dark theme, and the second is for light theme. If only a color is specified, the color is applied to both theme. `Color256` can be specified by 0-255 value like below: ```toml style = "223|112" # 223 for dark theme and 112 for light theme style = "223" # 223 for both theme ``` ### `[search]` section `[search]` section defines option for Keyword search. | Key | Value | Default | Description | | ----------------- | ----------------------------- | ------- | ------------------------------------------------------- | | numeric_search | Exact, Partial | Exact | Whether numeric keywords match exactly or partially | | nonnumeric_search | Exact, Partial | Partial | Whether non-numeric keywords match exactly or partially | | logic | And, Or, Nand, Nor | And | Logical operation between keywords | | case | Smart, Insensitive, Sensitive | Smart | Case sensitivity in search | #### `case` `case` is case sensitivity in search. - `Smart`: If keyword contains uppercase character, case sensitive search. Otherwise case insensitive search - `Insensitive`: case insensitive search - `Sensitive`: case sensitive search ### `[display]` section `[display]` section defines option for output display. | Key | Value | Default | Description | | --------------------- | --------------------- | ---------------- | ---------------------------------------------------------------------------- | | show_self | true, false | false | Whether the self process ( `procs` ) is shown | | show_self_parents | true, false | false | Whether the parents which have self as the only child process are shown | | show_thread | true, false | false | Whether the thread information is shown ( Linux only ) | | show_thread_in_tree | true, false | true | Whether the thread information is shown in tree mode ( Linux only ) | | show_parent_in_tree | true, false | true | Whether the parent process is shown in tree mode | | show_children_in_tree | true, false | true | Whether the children processes are shown in tree mode | | show_header | true, false | true | Whether header row is shown | | show_footer | true, false | false | Whether footer row is shown | | show_kthreads | true, false | true | Whether processes which belong to kthread are shown ( Linux only ) | | cut_to_terminal | true, false | true | Whether output lines are truncated for output into terminal | | cut_to_pager | true, false | false | Whether output lines are truncated for output into pager | | cut_to_pipe | true, false | false | Whether output lines are truncated for output into pipe | | color_mode | Auto, Always, Disable | Auto | The default behavior of output coloring without `--color` commandline option | | separator | [String] | │ | String used as Separator | | ascending | [String] | ▲ | Ascending sort indicator | | descending | [String] | ▼ | Descending sort indicator | | tree_symbols | [String; 5] | [│, ─, ┬, ├, └] | Symbols used by tree view | | abbr_sid | true, false | true | Whether machine SID is abbreviated ( Windows only ) | | theme | Auto, Dark, Light | Auto | Default theme | If `color_mode` is `Auto`, color is enabled for terminal and pager, disabled for pipe. If `theme` is `Auto`, theme is detected from terminal automatically. Some terminal don't support the automatic detection, so `Dark` or `Light` can be specified explicitly. #### `abbr_sid` Windows SID is too long, so it is abbreviated by default. If `abbr_sid` is `false`, SID is fully shown like below: ```text S-1-5-21-789457439-2186958450-1652286173-1001 ``` If `abbr_sid` is `true`, SID is shown like below: ```text S-1-5-21-...-1001 ``` ### `[sort]` section `[sort]` section defines the column used for sort and sort order. | Key | Value | Default | Description | | ------ | --------------------- | --------- | ------------------------------- | | column | [Number] | 0 | Column number to used for sort | | order | Ascending, Descending | Ascending | Sort order | If `column` is 0, value is sorted by the left column. ### `[docker]` section `[docker]` section defines how to communicate to docker daemon. | Key | Value | Default | Description | | ---- | ------ | --------------------------- | ----------------------------------- | | path | [Path] | unix:///var/run/docker.sock | UNIX domain socket to docker daemon | ### `[pager]` section `[pager]` section defines the behavior of pager. | Key | Value | Default | Description | | ------------ | --------------------- | -------- | ------------------------------------------------------------------------ | | mode | Auto, Always, Disable | Auto | The default behavior of pager usage without `--pager` commandline option | | detect_width | true, false | false | Whether `auto` mode detects terminal width overflow | | use_builtin | true, false | false | Whether built-in pager is used | | command | [Command] | less -SR | Pager command | If `mode` is `Auto`, pager is used only when output lines exceed terminal height. Default pager is `less -SR` ( if `less` is not found, `more -f` ). procs-0.14.9/man/procs.1.adoc000064400000000000000000000035011046102023000137340ustar 00000000000000= procs(1) :doctype: manpage :manmanual: User Commands :mansource: procs :man-linkstyle: pass:[blue R < >] == NAME procs - a replacement for `ps` written in Rust == SYNOPSIS *procs* [OPTIONS] [KEYWORDS] == DESCRIPTION *procs* is a command-line tool that provides an alternative to the `ps` command. == OPTIONS *--and*:: Show processes that match all keywords. *--or*:: Show processes that match any keyword. *--nand*:: Show processes unless they match all keywords. *--nor*:: Show processes unless they match any keyword. *--watch*:: Enable watch mode for real-time updates. *--watch-interval *:: Set the update interval for watch mode. *--tree*:: Display processes in a tree view. *--sorta *:: Sort processes in ascending order by the specified column. *--sortd *:: Sort processes in descending order by the specified column. *--insert *:: Insert a new column at the position of `Slot` or `MultiSlot`. *--gen-completion*:: Generate shell completion files for supported shells. == EXAMPLES *Show all processes*:: procs *Search by non-numeric keyword*:: procs zsh *Search by numeric keyword*:: procs --or 6000 60000 60001 16723 *Show Docker container name*:: procs growi == PAGER On Linux and macOS, `less` is the default pager. If not available, `more` is used. Built-in pager can be used by configuring `use_builtin`. On Windows, the built-in pager is always used. == WATCH MODE SHORTCUTS If `--watch` or `--watch-interval ` option is used, procs automatically updates output like `top`. Keyboard shortcuts are available for control. *n*:: Change the sort column to the next column *p*:: Change the sort column to the previous column *a*:: Change the sort order to ascending *d*:: Change the sort order to descending *q*:: Quit == RESOURCES *Project source code:* https://github.com/dalance/procs procs-0.14.9/snapcraft.yaml000064400000000000000000000010431046102023000137100ustar 00000000000000name: procs version: &version v0.14.9 summary: A modern replacement for ps written in Rust description: | procs is a tool to display process information. base: core18 license: MIT confinement: strict architectures: - build-on: amd64 - build-on: i386 - build-on: ppc64el - build-on: arm64 - build-on: armhf apps: procs: command: procs parts: procs: source: https://github.com/dalance/procs.git source-tag: *version plugin: rust stage-packages: - libc6 - libgcc1 - libstdc++6 - zlib1g procs-0.14.9/src/column.rs000064400000000000000000000156531046102023000135110ustar 00000000000000use crate::config::{Config, ConfigColumnAlign, ConfigSortOrder}; use crate::process::ProcessInfo; pub trait Column { fn add(&mut self, proc: &ProcessInfo); fn available(&self) -> bool { true } fn sortable(&self) -> bool { true } fn display_header( &self, align: &ConfigColumnAlign, order: Option, config: &Config, ) -> String; fn display_unit(&self, align: &ConfigColumnAlign) -> String; fn display_content(&self, pid: i32, align: &ConfigColumnAlign) -> Option; fn find_partial(&self, pid: i32, keyword: &str, content_to_lowercase: bool) -> bool; fn find_exact(&self, pid: i32, keyword: &str, content_to_lowercase: bool) -> bool; fn sorted_pid(&self, order: &ConfigSortOrder) -> Vec; fn apply_visible(&mut self, visible_pids: &[i32]); fn reset_width( &mut self, order: Option, config: &Config, max_width: Option, min_width: Option, ); fn update_width(&mut self, pid: i32, max_width: Option); fn get_width(&self) -> usize; } #[macro_export] macro_rules! column_default_display_header { () => { fn display_header( &self, align: &$crate::config::ConfigColumnAlign, order: Option<$crate::config::ConfigSortOrder>, config: &$crate::config::Config, ) -> String { if let Some(order) = order { let header = match order { $crate::config::ConfigSortOrder::Ascending => { format!("{}:{}", self.header, config.display.ascending) } $crate::config::ConfigSortOrder::Descending => { format!("{}:{}", self.header, config.display.descending) } }; $crate::util::adjust(&header, self.width, align) } else { $crate::util::adjust(&self.header, self.width, align) } } }; } #[macro_export] macro_rules! column_default_display_unit { () => { fn display_unit(&self, align: &$crate::config::ConfigColumnAlign) -> String { $crate::util::adjust(&self.unit, self.width, align) } }; } #[macro_export] macro_rules! column_default_display_content { () => { fn display_content( &self, pid: i32, align: &$crate::config::ConfigColumnAlign, ) -> Option { self.fmt_contents .get(&pid) .map(|content| $crate::util::adjust(content, self.width, align)) } }; } #[macro_export] macro_rules! column_default_find_partial { () => { fn find_partial(&self, pid: i32, keyword: &str, content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { if content_to_lowercase { content.to_ascii_lowercase().find(keyword).is_some() } else { content.find(keyword).is_some() } } else { false } } }; } #[macro_export] macro_rules! column_default_find_exact { () => { fn find_exact(&self, pid: i32, keyword: &str, content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { if content_to_lowercase { content.to_ascii_lowercase() == keyword } else { content == keyword } } else { false } } }; } #[macro_export] macro_rules! column_default_sorted_pid { ($x:ty) => { fn sorted_pid(&self, order: &$crate::config::ConfigSortOrder) -> Vec { let mut contents: Vec<(&i32, &$x)> = self.raw_contents.iter().collect(); contents.sort_by_key(|&(_x, y)| y); if matches!(*order, $crate::config::ConfigSortOrder::Descending) { contents.reverse() } contents.iter().map(|(x, _y)| **x).collect() } }; } #[macro_export] macro_rules! column_default_apply_visible { () => { fn apply_visible(&mut self, _visible_pids: &[i32]) {} }; } #[macro_export] macro_rules! column_default_reset_width { () => { fn reset_width( &mut self, order: Option<$crate::config::ConfigSortOrder>, config: &$crate::config::Config, max_width: Option, min_width: Option, ) { // +1 for spacing between header and sort indicator let sorted_space = if let Some(order) = order { match order { $crate::config::ConfigSortOrder::Ascending => { unicode_width::UnicodeWidthStr::width(config.display.ascending.as_str()) + 1 } $crate::config::ConfigSortOrder::Descending => { unicode_width::UnicodeWidthStr::width(config.display.descending.as_str()) + 1 } } } else { 0 }; let header_len = unicode_width::UnicodeWidthStr::width(self.header.as_str()); let unit_len = unicode_width::UnicodeWidthStr::width(self.unit.as_str()); self.width = std::cmp::max(header_len + sorted_space, unit_len); if let Some(min_width) = min_width { self.width = std::cmp::max(self.width, min_width); } if let Some(max_width) = max_width { self.width = std::cmp::min(self.width, max_width); } } }; } #[macro_export] macro_rules! column_default_update_width { () => { fn update_width(&mut self, pid: i32, max_width: Option) { if let Some(content) = self.fmt_contents.get(&pid) { let content_len = unicode_width::UnicodeWidthStr::width(content.as_str()); self.width = cmp::max(content_len, self.width); if let Some(max_width) = max_width { self.width = std::cmp::min(self.width, max_width); } } } }; } #[macro_export] macro_rules! column_default_get_width { () => { fn get_width(&self) -> usize { self.width } }; } #[macro_export] macro_rules! column_default { ($x:ty) => { $crate::column_default_display_header!(); $crate::column_default_display_unit!(); $crate::column_default_display_content!(); $crate::column_default_find_partial!(); $crate::column_default_find_exact!(); $crate::column_default_sorted_pid!($x); $crate::column_default_apply_visible!(); $crate::column_default_reset_width!(); $crate::column_default_update_width!(); $crate::column_default_get_width!(); }; } procs-0.14.9/src/columns/ccgroup.rs000064400000000000000000000053411046102023000153270ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use regex::Regex; use std::cmp; use std::collections::HashMap; pub struct Ccgroup { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, pat_user: Regex, pat_machine: Regex, pat_lxc_monitor: Regex, pat_lxc_payload: Regex, pat_scope: Regex, pat_service: Regex, pat_slice: Regex, } impl Ccgroup { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Cgroup (compressed)")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, pat_user: Regex::new(r"/user-([^/]*)\.slice").unwrap(), pat_machine: Regex::new(r"/machine-([^/]*)\.scope").unwrap(), pat_lxc_monitor: Regex::new(r"/lxc\.monitor\.([^/]*)").unwrap(), pat_lxc_payload: Regex::new(r"/lxc\.payload\.([^/]*)").unwrap(), pat_scope: Regex::new(r"/([^/]*)\.scope").unwrap(), pat_service: Regex::new(r"/([^/]*)\.service").unwrap(), pat_slice: Regex::new(r"/([^/]*)\.slice").unwrap(), } } } macro_rules! replace { ( $x: ident, $pat: expr, $fmt: literal) => { if let Some(x) = $pat.captures(&$x) { $pat.replace(&$x, &format!($fmt, &x[1])).to_string() } else { $x } }; } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Ccgroup { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(cgroups) = &proc.curr_proc.cgroups() { let name = cgroups .last() .map_or_else(|| "".to_string(), |x| x.pathname.to_string()); let name = name.replace("/system.slice", "/[S]"); let name = name.replace("/user.slice", "/[U]"); let name = replace!(name, self.pat_user, "/[U:{}]"); let name = name.replace("/machine.slice", "/[M]"); let name = replace!(name, self.pat_machine, "/[SNC:{}]"); let name = replace!(name, self.pat_lxc_monitor, "/[LXC:{}]"); let name = replace!(name, self.pat_lxc_payload, "/[lxc:{}]"); let name = replace!(name, self.pat_scope, "/!{}"); let name = replace!(name, self.pat_service, "/{}"); replace!(name, self.pat_slice, "/[{}]") } else { "".to_string() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/cgroup.rs000064400000000000000000000022541046102023000151640ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Cgroup { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Cgroup { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Cgroup")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Cgroup { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(cgroups) = &proc.curr_proc.cgroups() { cgroups .last() .map_or_else(|| "".to_string(), |x| x.pathname.to_string()) } else { "".to_string() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/command.rs000064400000000000000000000071451046102023000153070ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Command { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Command { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Command")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Command { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(cmd) = &proc.curr_proc.cmdline() { if !cmd.is_empty() { let mut cmd = cmd .iter() .cloned() .map(|mut x| { x.push(' '); x }) .collect::(); cmd.pop(); cmd = cmd.replace(['\n', '\t'], " "); cmd } else { format!("[{}]", proc.curr_proc.stat().comm) } } else { proc.curr_proc.stat().comm.clone() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for Command { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(path) = &proc.curr_path { if !path.cmd.is_empty() { let mut cmd = path .cmd .iter() .cloned() .map(|mut x| { x.push(' '); x }) .collect::(); cmd.pop(); cmd = cmd.replace(['\n', '\t'], " "); cmd } else { String::from("") } } else { String::from("") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "windows")] impl Column for Command { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = proc.command.clone(); let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for Command { fn add(&mut self, proc: &ProcessInfo) { let command = if proc.curr_proc.arg.is_empty() { let comm = crate::util::ptr_to_cstr(proc.curr_proc.info.comm.as_ref()); if let Ok(comm) = comm { format!("[{}]", comm.to_string_lossy()) } else { String::from("") } } else { let mut x = String::from(""); for arg in &proc.curr_proc.arg { x.push_str(&arg); x.push_str(" "); } x }; let fmt_content = command; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/context_sw.rs000064400000000000000000000042551046102023000160650ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct ContextSw { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl ContextSw { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("ContextSw")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for ContextSw { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { if status.voluntary_ctxt_switches.is_some() && status.nonvoluntary_ctxt_switches.is_some() { let sw = status.voluntary_ctxt_switches.unwrap() + status.nonvoluntary_ctxt_switches.unwrap(); (bytify(sw), sw) } else { (String::new(), 0) } } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for ContextSw { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.ptinfo.pti_csw as u64; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for ContextSw { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_proc.info.rusage.nvcsw + proc.curr_proc.info.rusage.nivcsw) as u64; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/cpu_time.rs000064400000000000000000000051471046102023000154760ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, util, Column}; use std::cmp; use std::collections::HashMap; pub struct CpuTime { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl CpuTime { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("CPU Time")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for CpuTime { fn add(&mut self, proc: &ProcessInfo) { let time_sec = (proc.curr_proc.stat().utime + proc.curr_proc.stat().stime) / procfs::ticks_per_second(); let fmt_content = util::parse_time(time_sec); let raw_content = time_sec; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for CpuTime { fn add(&mut self, proc: &ProcessInfo) { let time_sec = (proc.curr_task.ptinfo.pti_total_user + proc.curr_task.ptinfo.pti_total_system) / 1_000_000_000u64; let fmt_content = util::parse_time(time_sec); let raw_content = time_sec; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for CpuTime { fn add(&mut self, proc: &ProcessInfo) { let time_sec = (proc.cpu_info.curr_sys + proc.cpu_info.curr_user) / 10_000_000u64; let fmt_content = util::parse_time(time_sec); let raw_content = time_sec; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for CpuTime { fn add(&mut self, proc: &ProcessInfo) { let time_sec = ((proc.curr_proc.info.rusage.utime.sec * 1_000_000i64 + proc.curr_proc.info.rusage.utime.usec + proc.curr_proc.info.rusage.stime.sec * 1_000_000i64 + proc.curr_proc.info.rusage.stime.usec) / 1_000_000) as u64; let fmt_content = util::parse_time(time_sec); let raw_content = time_sec; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/docker.rs000064400000000000000000000123021046102023000151270ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use dockworker::container::ContainerFilters; use std::cmp; use std::collections::HashMap; use tokio::runtime::Runtime; pub struct Docker { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[cfg(any(target_os = "linux", target_os = "android"))] containers: HashMap, #[cfg(target_os = "macos")] containers: HashMap, available: bool, } #[cfg(any(target_os = "linux", target_os = "android"))] impl Docker { pub fn new(header: Option, path: &str) -> Self { let header = header.unwrap_or_else(|| String::from("Docker")); let unit = String::new(); let mut containers = HashMap::new(); let mut available = true; if let Ok(docker) = dockworker::Docker::connect_with_unix(path) { let rt = Runtime::new().unwrap(); if let Ok(cont) = rt.block_on(docker.list_containers(None, None, None, ContainerFilters::new())) { for c in cont { // remove the first letter '/' from container name let name = String::from(&c.Names[0][1..]); containers.insert(c.Id, name); } } else { available = false; } } else { available = false; } Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, containers, available, } } } #[cfg(target_os = "macos")] impl Docker { pub fn new(header: Option, path: &str) -> Self { let header = header.unwrap_or_else(|| String::from("Docker")); let unit = String::from(""); let mut containers = HashMap::new(); let mut available = true; if let Ok(docker) = dockworker::Docker::connect_with_unix(path) { let rt = Runtime::new().unwrap(); if let Ok(cont) = rt.block_on(docker.list_containers(None, None, None, ContainerFilters::new())) { for c in cont { // remove the first letter '/' from container name let name = String::from(&c.Names[0][1..]); if let Ok(processes) = rt.block_on(docker.processes(c.Id.as_str())) { for p in processes { if let Ok(pid) = p.pid.parse::() { containers.insert(pid, name.clone()); } } } } } else { available = false; } } else { available = false; } Docker { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, containers, available, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Docker { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(cgroups) = proc.curr_proc.cgroups() { let mut ret = String::new(); for cgroup in cgroups { let cgroup_name = cgroup.pathname.clone(); if cgroup_name.starts_with("/docker") { let container_id = cgroup_name.replace("/docker/", ""); if let Some(name) = self.containers.get(&container_id) { ret = name.to_string(); break; } else { ret = String::from("?"); break; } } else if cgroup_name.starts_with("/system.slice/docker-") { let container_id = cgroup_name .replace("/system.slice/docker-", "") .replace(".scope", ""); if let Some(name) = self.containers.get(&container_id) { ret = name.to_string(); break; } else { ret = String::from("?"); break; } } } ret } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn available(&self) -> bool { self.available } column_default!(String); } #[cfg(target_os = "macos")] impl Column for Docker { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(name) = self.containers.get(&proc.pid) { name.to_string() } else { String::from("") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn available(&self) -> bool { self.available } column_default!(String); } procs-0.14.9/src/columns/eip.rs000064400000000000000000000016531046102023000144440ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Eip { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Eip { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("EIP")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for Eip { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().kstkeip; let fmt_content = format!("{raw_content:016x}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/elapsed_time.rs000064400000000000000000000100331046102023000163120ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; #[cfg(not(target_os = "windows"))] use chrono::offset::TimeZone; #[cfg(any(target_os = "linux", target_os = "android"))] use chrono::DateTime; use chrono::{Duration, Local}; #[cfg(any(target_os = "linux", target_os = "android"))] use once_cell::sync::Lazy; use std::cmp; use std::collections::HashMap; #[cfg(any(target_os = "linux", target_os = "android"))] static TICKS_PER_SECOND: Lazy = Lazy::new(procfs::ticks_per_second); pub struct ElapsedTime { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[cfg(any(target_os = "linux", target_os = "android"))] boot_time: DateTime, } impl ElapsedTime { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Elapsed")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, #[cfg(any(target_os = "linux", target_os = "android"))] boot_time: procfs::boot_time().unwrap_or_else(|_| Local.timestamp_opt(0, 0).unwrap()), } } } fn format_duration(duration: Duration) -> String { let years = duration.num_weeks() as f64 / 52.0; let weeks = duration.num_days() as f64 / 7.0; let days = duration.num_hours() as f64 / 24.0; let hours = duration.num_minutes() as f64 / 60.0; let minutes = duration.num_seconds() as f64 / 60.0; let seconds = duration.num_seconds(); if years > 1.0 { format!("{years:.1}years") } else if weeks > 1.0 { format!("{weeks:.1}weeks") } else if days > 1.0 { format!("{days:.1}days") } else if hours > 1.0 { format!("{hours:.1}hours") } else if minutes > 1.0 { format!("{minutes:.1}minutes") } else { format!("{seconds:.1}seconds") } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for ElapsedTime { fn add(&mut self, proc: &ProcessInfo) { let starttime = proc.curr_proc.stat().starttime; let seconds_since_boot = starttime as f32 / *TICKS_PER_SECOND as f32; let start_time = self.boot_time + Duration::try_milliseconds((seconds_since_boot * 1000.0) as i64).unwrap_or_default(); let raw_content = Local::now().signed_duration_since(start_time); let fmt_content = format_duration(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(Duration); } #[cfg(target_os = "macos")] impl Column for ElapsedTime { fn add(&mut self, proc: &ProcessInfo) { let start_time = Local .timestamp_opt(proc.curr_task.pbsd.pbi_start_tvsec as i64, 0) .unwrap(); let raw_content = Local::now().signed_duration_since(start_time); let fmt_content = format_duration(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(Duration); } #[cfg(target_os = "windows")] impl Column for ElapsedTime { fn add(&mut self, proc: &ProcessInfo) { let raw_content = Local::now().signed_duration_since(proc.start_time); let fmt_content = format_duration(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(Duration); } #[cfg(target_os = "freebsd")] impl Column for ElapsedTime { fn add(&mut self, proc: &ProcessInfo) { let start_time = Local .timestamp_opt(proc.curr_proc.info.start.sec as i64, 0) .unwrap(); let raw_content = Local::now().signed_duration_since(start_time); let fmt_content = format_duration(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(Duration); } procs-0.14.9/src/columns/empty.rs000064400000000000000000000015411046102023000150210ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Empty { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Empty { pub fn new() -> Self { let header = String::new(); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for Empty { fn add(&mut self, proc: &ProcessInfo) { let raw_content = String::new(); let fmt_content = String::new(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/env.rs000064400000000000000000000037171046102023000144620ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use std::path::PathBuf; pub struct Env { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[allow(dead_code)] procfs: Option, } impl Env { pub fn new(header: Option, procfs: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Env")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, procfs, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Env { fn add(&mut self, proc: &ProcessInfo) { let mut fmt_content = String::new(); if let Ok(proc) = crate::util::process_new(proc.pid, &self.procfs) { if let Ok(envs) = proc.environ() { for (k, v) in envs { fmt_content.push_str(&format!( "{}=\"{}\" ", k.to_string_lossy(), v.to_string_lossy().replace('\"', "\\\"") )); } } } let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for Env { fn add(&mut self, proc: &ProcessInfo) { let mut fmt_content = String::new(); for env in &proc.curr_proc.env { fmt_content.push_str(&format!("{} ", env.replace('\"', "\\\""))); } let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/esp.rs000064400000000000000000000016531046102023000144560ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Esp { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Esp { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("ESP")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for Esp { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().kstkesp; let fmt_content = format!("{raw_content:016x}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/file_name.rs000064400000000000000000000030531046102023000156020ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct FileName { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl FileName { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("FileName")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for FileName { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().comm.clone(); let fmt_content = raw_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for FileName { fn add(&mut self, proc: &ProcessInfo) { let comm = crate::util::ptr_to_cstr(proc.curr_proc.info.comm.as_ref()); let comm = if let Ok(comm) = comm { comm.to_string_lossy().into_owned() } else { String::from("") }; let fmt_content = comm; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/gid.rs000064400000000000000000000050711046102023000144300ustar 00000000000000use crate::process::ProcessInfo; #[cfg(target_os = "windows")] use crate::util::format_sid; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Gid { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[allow(dead_code)] abbr_sid: bool, } impl Gid { pub fn new(header: Option, abbr_sid: bool) -> Self { let header = header.unwrap_or_else(|| String::from("GID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, abbr_sid, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Gid { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let gid = status.egid; (format!("{gid}"), gid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for Gid { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_task.pbsd.pbi_gid; let fmt_content = format!("{}", gid); let raw_content = gid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "windows")] impl Column for Gid { fn add(&mut self, proc: &ProcessInfo) { let mut sid = &proc.groups[0].sid; let mut kind = u64::MAX; for g in &proc.groups { if g.sid.len() > 3 && g.sid[1] == 5 && g.sid[2] == 32 && kind > g.sid[3] { sid = &g.sid; kind = g.sid[3]; } } let fmt_content = format_sid(sid, self.abbr_sid); let raw_content = sid[sid.len() - 1] as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for Gid { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_proc.info.svgid; let fmt_content = format!("{}", gid); let raw_content = gid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/gid_fs.rs000064400000000000000000000020301046102023000151100ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct GidFs { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl GidFs { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("FGID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for GidFs { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let gid = status.fgid; (format!("{gid}"), gid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/gid_real.rs000064400000000000000000000035001046102023000154260ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct GidReal { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl GidReal { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("RGID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for GidReal { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let gid = status.rgid; (format!("{gid}"), gid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for GidReal { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_task.pbsd.pbi_rgid; let fmt_content = format!("{}", gid); let raw_content = gid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for GidReal { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_proc.info.rgid; let fmt_content = format!("{}", gid); let raw_content = gid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/gid_saved.rs000064400000000000000000000035071046102023000156140ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct GidSaved { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl GidSaved { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("SGID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for GidSaved { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let gid = status.sgid; (format!("{gid}"), gid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for GidSaved { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_task.pbsd.pbi_svgid; let fmt_content = format!("{}", gid); let raw_content = gid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for GidSaved { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_proc.info.svgid; let fmt_content = format!("{}", gid); let raw_content = gid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/group.rs000064400000000000000000000067121046102023000150240ustar 00000000000000use crate::process::ProcessInfo; #[cfg(target_os = "windows")] use crate::util::format_sid; #[cfg(not(target_os = "windows"))] use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; #[cfg(not(target_os = "windows"))] use uzers::Groups; pub struct Group { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[allow(dead_code)] abbr_sid: bool, } impl Group { pub fn new(header: Option, abbr_sid: bool) -> Self { let header = header.unwrap_or_else(|| String::from("Group")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, abbr_sid, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Group { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let gid = status.egid; if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for Group { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_task.pbsd.pbi_gid; let fmt_content = if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{}", gid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "windows")] impl Column for Group { fn add(&mut self, proc: &ProcessInfo) { let mut sid_name = &proc.groups[0]; let mut kind = u64::MAX; for g in &proc.groups { if g.sid.len() > 3 && g.sid[1] == 5 && g.sid[2] == 32 && kind > g.sid[3] { sid_name = g; kind = g.sid[3]; } } let fmt_content = if let Some(name) = &sid_name.name { name.clone() } else { format_sid(&sid_name.sid, self.abbr_sid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for Group { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_proc.info.svgid; let fmt_content = if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/group_fs.rs000064400000000000000000000024711046102023000155120ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Groups; pub struct GroupFs { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl GroupFs { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("File System Group")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for GroupFs { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let gid = status.fgid; if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/group_real.rs000064400000000000000000000050401046102023000160200ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Groups; pub struct GroupReal { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl GroupReal { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Real Group")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for GroupReal { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let gid = status.rgid; if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for GroupReal { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_task.pbsd.pbi_rgid; let fmt_content = if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{}", gid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for GroupReal { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_proc.info.rgid; let fmt_content = if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/group_saved.rs000064400000000000000000000050501046102023000162000ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Groups; pub struct GroupSaved { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl GroupSaved { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Saved Group")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for GroupSaved { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let gid = status.sgid; if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for GroupSaved { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_task.pbsd.pbi_svgid; let fmt_content = if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{}", gid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for GroupSaved { fn add(&mut self, proc: &ProcessInfo) { let gid = proc.curr_proc.info.svgid; let fmt_content = if let Some(group) = USERS_CACHE.with(|x| x.borrow_mut().get_group_by_gid(gid)) { format!("{}", group.name().to_string_lossy()) } else { format!("{gid}") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/maj_flt.rs000064400000000000000000000040731046102023000153020ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct MajFlt { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl MajFlt { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("MajorFaults")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for MajFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().majflt; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for MajFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.ptinfo.pti_pageins as u64; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for MajFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.page_fault_count; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for MajFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.rusage.majflt as u64; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/min_flt.rs000064400000000000000000000034031046102023000153120ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct MinFlt { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl MinFlt { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("MinorFaults")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for MinFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().minflt; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for MinFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_task.ptinfo.pti_faults - proc.curr_task.ptinfo.pti_pageins) as u64; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for MinFlt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.rusage.minflt as u64; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/multi_slot.rs000064400000000000000000000015551046102023000160630ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct MultiSlot { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl MultiSlot { pub fn new() -> Self { let header = String::new(); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for MultiSlot { fn add(&mut self, proc: &ProcessInfo) { let raw_content = String::new(); let fmt_content = String::new(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/nice.rs000064400000000000000000000032611046102023000146020ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Nice { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Nice { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Nice")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Nice { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().nice; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "macos")] impl Column for Nice { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.pbsd.pbi_nice as i64; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "freebsd")] impl Column for Nice { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.nice as i64; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } procs-0.14.9/src/columns/os_freebsd.rs000064400000000000000000000456241046102023000160100ustar 00000000000000pub mod command; pub mod context_sw; pub mod cpu_time; pub mod elapsed_time; pub mod empty; pub mod env; pub mod file_name; pub mod gid; pub mod gid_real; pub mod gid_saved; pub mod group; pub mod group_real; pub mod group_saved; pub mod maj_flt; pub mod min_flt; pub mod multi_slot; pub mod nice; pub mod pgid; pub mod pid; pub mod ppid; pub mod priority; pub mod processor; pub mod read_bytes; pub mod separator; pub mod session; pub mod shd_pnd; pub mod sig_blk; pub mod sig_cgt; pub mod sig_ign; pub mod slot; pub mod start_time; pub mod state; pub mod threads; pub mod tree; pub mod tree_slot; pub mod tty; pub mod uid; pub mod uid_real; pub mod uid_saved; pub mod usage_cpu; pub mod usage_mem; pub mod user; pub mod user_real; pub mod user_saved; pub mod vm_data; pub mod vm_exe; pub mod vm_hwm; pub mod vm_rss; pub mod vm_size; pub mod vm_stack; pub mod wchan; pub mod write_bytes; pub use self::command::Command; pub use self::context_sw::ContextSw; pub use self::cpu_time::CpuTime; pub use self::elapsed_time::ElapsedTime; pub use self::empty::Empty; pub use self::env::Env; pub use self::file_name::FileName; pub use self::gid::Gid; pub use self::gid_real::GidReal; pub use self::gid_saved::GidSaved; pub use self::group::Group; pub use self::group_real::GroupReal; pub use self::group_saved::GroupSaved; pub use self::maj_flt::MajFlt; pub use self::min_flt::MinFlt; pub use self::multi_slot::MultiSlot; pub use self::nice::Nice; pub use self::pgid::Pgid; pub use self::pid::Pid; pub use self::ppid::Ppid; pub use self::priority::Priority; pub use self::processor::Processor; pub use self::read_bytes::ReadBytes; pub use self::separator::Separator; pub use self::session::Session; pub use self::shd_pnd::ShdPnd; pub use self::sig_blk::SigBlk; pub use self::sig_cgt::SigCgt; pub use self::sig_ign::SigIgn; pub use self::slot::Slot; pub use self::start_time::StartTime; pub use self::state::State; pub use self::threads::Threads; pub use self::tree::Tree; pub use self::tree_slot::TreeSlot; pub use self::tty::Tty; pub use self::uid::Uid; pub use self::uid_real::UidReal; pub use self::uid_saved::UidSaved; pub use self::usage_cpu::UsageCpu; pub use self::usage_mem::UsageMem; pub use self::user::User; pub use self::user_real::UserReal; pub use self::user_saved::UserSaved; pub use self::vm_data::VmData; pub use self::vm_exe::VmExe; pub use self::vm_hwm::VmHwm; pub use self::vm_rss::VmRss; pub use self::vm_size::VmSize; pub use self::vm_stack::VmStack; pub use self::wchan::Wchan; pub use self::write_bytes::WriteBytes; use crate::column::Column; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::path::PathBuf; // --------------------------------------------------------------------------------------------------------------------- // ConfigColumnKind // --------------------------------------------------------------------------------------------------------------------- #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ConfigColumnKind { Command, ContextSw, CpuTime, ElapsedTime, Empty, Env, FileName, Gid, GidReal, GidSaved, Group, GroupReal, GroupSaved, MajFlt, MinFlt, MultiSlot, Nice, Pgid, Pid, Ppid, Priority, Processor, ReadBytes, Separator, Session, ShdPnd, Slot, SigBlk, SigCgt, SigIgn, StartTime, State, Threads, Tree, TreeSlot, Tty, Uid, UidReal, UidSaved, UsageCpu, UsageMem, User, UserReal, UserSaved, VmData, VmExe, VmHwm, VmRss, VmSize, VmStack, Wchan, WriteBytes, } // --------------------------------------------------------------------------------------------------------------------- // gen_column // --------------------------------------------------------------------------------------------------------------------- pub fn gen_column( kind: &ConfigColumnKind, header: Option, _docker_path: &str, separator: &str, abbr_sid: bool, tree_symbols: &[String; 5], procfs: Option, ) -> Box { match kind { ConfigColumnKind::Command => Box::new(Command::new(header)), ConfigColumnKind::ContextSw => Box::new(ContextSw::new(header)), ConfigColumnKind::CpuTime => Box::new(CpuTime::new(header)), ConfigColumnKind::ElapsedTime => Box::new(ElapsedTime::new(header)), ConfigColumnKind::Empty => Box::new(Empty::new()), ConfigColumnKind::Env => Box::new(Env::new(header, procfs)), ConfigColumnKind::FileName => Box::new(FileName::new(header)), ConfigColumnKind::Gid => Box::new(Gid::new(header, abbr_sid)), ConfigColumnKind::GidReal => Box::new(GidReal::new(header)), ConfigColumnKind::GidSaved => Box::new(GidSaved::new(header)), ConfigColumnKind::Group => Box::new(Group::new(header, abbr_sid)), ConfigColumnKind::GroupReal => Box::new(GroupReal::new(header)), ConfigColumnKind::GroupSaved => Box::new(GroupSaved::new(header)), ConfigColumnKind::MajFlt => Box::new(MajFlt::new(header)), ConfigColumnKind::MinFlt => Box::new(MinFlt::new(header)), ConfigColumnKind::MultiSlot => Box::new(MultiSlot::new()), ConfigColumnKind::Nice => Box::new(Nice::new(header)), ConfigColumnKind::Pgid => Box::new(Pgid::new(header)), ConfigColumnKind::Pid => Box::new(Pid::new(header)), ConfigColumnKind::Ppid => Box::new(Ppid::new(header)), ConfigColumnKind::Priority => Box::new(Priority::new(header)), ConfigColumnKind::Processor => Box::new(Processor::new(header)), ConfigColumnKind::ReadBytes => Box::new(ReadBytes::new(header)), ConfigColumnKind::Separator => Box::new(Separator::new(separator)), ConfigColumnKind::Session => Box::new(Session::new(header)), ConfigColumnKind::ShdPnd => Box::new(ShdPnd::new(header)), ConfigColumnKind::Slot => Box::new(Slot::new()), ConfigColumnKind::SigBlk => Box::new(SigBlk::new(header)), ConfigColumnKind::SigCgt => Box::new(SigCgt::new(header)), ConfigColumnKind::SigIgn => Box::new(SigIgn::new(header)), ConfigColumnKind::StartTime => Box::new(StartTime::new(header)), ConfigColumnKind::State => Box::new(State::new(header)), ConfigColumnKind::Threads => Box::new(Threads::new(header)), ConfigColumnKind::Tree => Box::new(Tree::new(tree_symbols)), ConfigColumnKind::TreeSlot => Box::new(TreeSlot::new()), ConfigColumnKind::Tty => Box::new(Tty::new(header)), ConfigColumnKind::Uid => Box::new(Uid::new(header, abbr_sid)), ConfigColumnKind::UidReal => Box::new(UidReal::new(header)), ConfigColumnKind::UidSaved => Box::new(UidSaved::new(header)), ConfigColumnKind::UsageCpu => Box::new(UsageCpu::new(header)), ConfigColumnKind::UsageMem => Box::new(UsageMem::new(header)), ConfigColumnKind::User => Box::new(User::new(header, abbr_sid)), ConfigColumnKind::UserReal => Box::new(UserReal::new(header)), ConfigColumnKind::UserSaved => Box::new(UserSaved::new(header)), ConfigColumnKind::VmData => Box::new(VmData::new(header)), ConfigColumnKind::VmExe => Box::new(VmExe::new(header)), ConfigColumnKind::VmHwm => Box::new(VmHwm::new(header)), ConfigColumnKind::VmRss => Box::new(VmRss::new(header)), ConfigColumnKind::VmSize => Box::new(VmSize::new(header)), ConfigColumnKind::VmStack => Box::new(VmStack::new(header)), ConfigColumnKind::Wchan => Box::new(Wchan::new(header)), ConfigColumnKind::WriteBytes => Box::new(WriteBytes::new(header)), } } // --------------------------------------------------------------------------------------------------------------------- // KIND_LIST // --------------------------------------------------------------------------------------------------------------------- pub static KIND_LIST: Lazy> = Lazy::new(|| { [ ( ConfigColumnKind::Command, ("Command", "Command with all arguments"), ), ( ConfigColumnKind::ContextSw, ("ContextSw", "Context switch count"), ), ( ConfigColumnKind::CpuTime, ("CpuTime", "Cumulative CPU time"), ), ( ConfigColumnKind::ElapsedTime, ("ElapsedTime", "Elapsed time"), ), (ConfigColumnKind::Empty, ("Empty", "Empty")), (ConfigColumnKind::Env, ("Env", "Environment variables")), (ConfigColumnKind::FileName, ("FileName", "File name")), (ConfigColumnKind::Gid, ("Gid", "Group ID")), (ConfigColumnKind::GidReal, ("GidReal", "Real group ID")), (ConfigColumnKind::GidSaved, ("GidSaved", "Saved group ID")), (ConfigColumnKind::Group, ("Group", "Group name")), ( ConfigColumnKind::GroupReal, ("GroupReal", "Real group name"), ), ( ConfigColumnKind::GroupSaved, ("GroupSaved", "Saved group name"), ), ( ConfigColumnKind::MajFlt, ("MajFlt", "Major page fault count"), ), ( ConfigColumnKind::MinFlt, ("MinFlt", "Minor page fault count"), ), ( ConfigColumnKind::MultiSlot, ("MultiSlot", "Slot for `--insert` option"), ), (ConfigColumnKind::Nice, ("Nice", "Nice value")), (ConfigColumnKind::Pgid, ("Pgid", "Process group ID")), (ConfigColumnKind::Pid, ("Pid", "Process ID")), (ConfigColumnKind::Ppid, ("Ppid", "Parent process ID")), (ConfigColumnKind::Priority, ("Priority", "Priority")), ( ConfigColumnKind::Processor, ("Processor", "Currently assigned processor"), ), ( ConfigColumnKind::ReadBytes, ("ReadBytes", "Read bytes from storage"), ), ( ConfigColumnKind::Separator, ("Separator", "Show | for column separation"), ), (ConfigColumnKind::Session, ("Session", "Process Session ID")), ( ConfigColumnKind::ShdPnd, ("ShdPnd", "Pending signal mask for process"), ), ( ConfigColumnKind::Slot, ("Slot", "Slot for `--insert` option"), ), (ConfigColumnKind::SigBlk, ("SigBlk", "Blocked signal mask")), (ConfigColumnKind::SigCgt, ("SigCgt", "Caught signal mask")), (ConfigColumnKind::SigIgn, ("SigIgn", "Ignored signal mask")), (ConfigColumnKind::StartTime, ("StartTime", "Starting time")), (ConfigColumnKind::State, ("State", "Process state")), (ConfigColumnKind::Threads, ("Threads", "Thread count")), ( ConfigColumnKind::TreeSlot, ("TreeSlot", "Slot for tree column"), ), (ConfigColumnKind::Tty, ("Tty", "Controlling TTY")), (ConfigColumnKind::Uid, ("Uid", "User ID")), (ConfigColumnKind::UidReal, ("UidReal", "Real user ID")), (ConfigColumnKind::UidSaved, ("UidSaved", "Saved user ID")), (ConfigColumnKind::UsageCpu, ("UsageCpu", "CPU utilization")), ( ConfigColumnKind::UsageMem, ("UsageMem", "Memory utilization"), ), (ConfigColumnKind::User, ("User", "User name")), (ConfigColumnKind::UserReal, ("UserReal", "Real user name")), ( ConfigColumnKind::UserSaved, ("UserSaved", "Saved user name"), ), (ConfigColumnKind::VmData, ("VmData", "Data size")), (ConfigColumnKind::VmExe, ("VmExe", "Text segments size")), (ConfigColumnKind::VmHwm, ("VmHwm", "Peak resident set size")), (ConfigColumnKind::VmRss, ("VmRss", "Resident set size")), (ConfigColumnKind::VmSize, ("VmSize", "Physical page size")), (ConfigColumnKind::VmStack, ("VmStack", "Stack size")), ( ConfigColumnKind::Wchan, ("Wchan", "Process sleeping kernel function"), ), ( ConfigColumnKind::WriteBytes, ("WriteBytes", "Write bytes to storage"), ), ] .iter() .cloned() .collect() }); // --------------------------------------------------------------------------------------------------------------------- // CONFIG_DEFAULT // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_DEFAULT: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Tty" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false [[columns]] kind = "MultiSlot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_LARGE // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_LARGE: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false align = "Left" [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "State" style = "ByState" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Nice" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Tty" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmSize" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmRss" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "ReadBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "WriteBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Slot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "StartTime" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true align = "Left" "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_ALL // --------------------------------------------------------------------------------------------------------------------- #[cfg(test)] pub static CONFIG_ALL: &str = r#" [[columns]] kind = "Command" style = "BrightRed" align = "Left" [[columns]] kind = "ContextSw" style = "BrightRed" align = "Right" [[columns]] kind = "CpuTime" style = "BrightGreen" align = "Center" [[columns]] kind = "ElapsedTime" style = "BrightYellow" [[columns]] kind = "Empty" style = "BrightYellow" [[columns]] kind = "Env" style = "BrightYellow" [[columns]] kind = "FileName" style = "BrightBlue" [[columns]] kind = "Gid" style = "White" [[columns]] kind = "GidReal" style = "White" [[columns]] kind = "GidSaved" style = "White" [[columns]] kind = "Group" style = "White" [[columns]] kind = "GroupReal" style = "White" [[columns]] kind = "GroupSaved" style = "White" [[columns]] kind = "MajFlt" style = "BrightCyan" [[columns]] kind = "MinFlt" style = "BrightWhite" [[columns]] kind = "MultiSlot" style = "BrightWhite" [[columns]] kind = "Nice" style = "Red" [[columns]] kind = "Pgid" style = "Yellow" [[columns]] kind = "Pid" style = "Green" [[columns]] kind = "Ppid" style = "Yellow" [[columns]] kind = "Priority" style = "Blue" [[columns]] kind = "Processor" style = "Magenta" [[columns]] kind = "ReadBytes" style = "Cyan" [[columns]] kind = "Separator" style = "White" [[columns]] kind = "Session" style = "Yellow" [[columns]] kind = "ShdPnd" style = "White" [[columns]] kind = "SigBlk" style = "White" [[columns]] kind = "SigCgt" style = "White" [[columns]] kind = "SigIgn" style = "White" [[columns]] kind = "StartTime" style = "White" [[columns]] kind = "State" style = "White" [[columns]] kind = "Threads" style = "White" [[columns]] kind = "TreeSlot" style = "BrightWhite" [[columns]] kind = "Tty" style = "White" [[columns]] kind = "Uid" style = "White" [[columns]] kind = "UidReal" style = "White" [[columns]] kind = "UidSaved" style = "White" [[columns]] kind = "UsageCpu" style = "White" [[columns]] kind = "UsageMem" style = "White" [[columns]] kind = "User" style = "White" [[columns]] kind = "UserReal" style = "White" [[columns]] kind = "UserSaved" style = "White" [[columns]] kind = "VmData" style = "ByUnit" [[columns]] kind = "VmExe" style = "ByUnit" [[columns]] kind = "VmHwm" style = "ByUnit" [[columns]] kind = "VmRss" style = "ByUnit" [[columns]] kind = "VmSize" style = "ByUnit" [[columns]] kind = "VmStack" style = "ByUnit" [[columns]] kind = "Wchan" style = "White" [[columns]] kind = "WriteBytes" style = "White" "#; procs-0.14.9/src/columns/os_linux.rs000064400000000000000000000644531046102023000155360ustar 00000000000000pub mod ccgroup; pub mod cgroup; pub mod command; pub mod context_sw; pub mod cpu_time; #[cfg(feature = "docker")] pub mod docker; pub mod eip; pub mod elapsed_time; pub mod empty; pub mod env; pub mod esp; pub mod file_name; pub mod gid; pub mod gid_fs; pub mod gid_real; pub mod gid_saved; pub mod group; pub mod group_fs; pub mod group_real; pub mod group_saved; pub mod maj_flt; pub mod min_flt; pub mod multi_slot; pub mod nice; pub mod pgid; pub mod pid; pub mod policy; pub mod ppid; pub mod priority; pub mod processor; pub mod read_bytes; pub mod rt_priority; pub mod sec_context; pub mod separator; pub mod session; pub mod shd_pnd; pub mod sig_blk; pub mod sig_cgt; pub mod sig_ign; pub mod sig_pnd; pub mod slot; pub mod ssb; pub mod start_time; pub mod state; pub mod tcp_port; pub mod threads; pub mod tree; pub mod tree_slot; pub mod tty; pub mod udp_port; pub mod uid; pub mod uid_fs; pub mod uid_login; pub mod uid_real; pub mod uid_saved; pub mod usage_cpu; pub mod usage_mem; pub mod user; pub mod user_fs; pub mod user_login; pub mod user_real; pub mod user_saved; pub mod vm_data; pub mod vm_exe; pub mod vm_hwm; pub mod vm_lib; pub mod vm_lock; pub mod vm_peak; pub mod vm_pin; pub mod vm_pte; pub mod vm_rss; pub mod vm_size; pub mod vm_stack; pub mod vm_swap; pub mod wchan; pub mod work_dir; pub mod write_bytes; pub use self::ccgroup::Ccgroup; pub use self::cgroup::Cgroup; pub use self::command::Command; pub use self::context_sw::ContextSw; pub use self::cpu_time::CpuTime; #[cfg(feature = "docker")] pub use self::docker::Docker; pub use self::eip::Eip; pub use self::elapsed_time::ElapsedTime; pub use self::empty::Empty; pub use self::env::Env; pub use self::esp::Esp; pub use self::file_name::FileName; pub use self::gid::Gid; pub use self::gid_fs::GidFs; pub use self::gid_real::GidReal; pub use self::gid_saved::GidSaved; pub use self::group::Group; pub use self::group_fs::GroupFs; pub use self::group_real::GroupReal; pub use self::group_saved::GroupSaved; pub use self::maj_flt::MajFlt; pub use self::min_flt::MinFlt; pub use self::multi_slot::MultiSlot; pub use self::nice::Nice; pub use self::pgid::Pgid; pub use self::pid::Pid; pub use self::policy::Policy; pub use self::ppid::Ppid; pub use self::priority::Priority; pub use self::processor::Processor; pub use self::read_bytes::ReadBytes; pub use self::rt_priority::RtPriority; pub use self::sec_context::SecContext; pub use self::separator::Separator; pub use self::session::Session; pub use self::shd_pnd::ShdPnd; pub use self::sig_blk::SigBlk; pub use self::sig_cgt::SigCgt; pub use self::sig_ign::SigIgn; pub use self::sig_pnd::SigPnd; pub use self::slot::Slot; pub use self::ssb::Ssb; pub use self::start_time::StartTime; pub use self::state::State; pub use self::tcp_port::TcpPort; pub use self::threads::Threads; pub use self::tree::Tree; pub use self::tree_slot::TreeSlot; pub use self::tty::Tty; pub use self::udp_port::UdpPort; pub use self::uid::Uid; pub use self::uid_fs::UidFs; pub use self::uid_login::UidLogin; pub use self::uid_real::UidReal; pub use self::uid_saved::UidSaved; pub use self::usage_cpu::UsageCpu; pub use self::usage_mem::UsageMem; pub use self::user::User; pub use self::user_fs::UserFs; pub use self::user_login::UserLogin; pub use self::user_real::UserReal; pub use self::user_saved::UserSaved; pub use self::vm_data::VmData; pub use self::vm_exe::VmExe; pub use self::vm_hwm::VmHwm; pub use self::vm_lib::VmLib; pub use self::vm_lock::VmLock; pub use self::vm_peak::VmPeak; pub use self::vm_pin::VmPin; pub use self::vm_pte::VmPte; pub use self::vm_rss::VmRss; pub use self::vm_size::VmSize; pub use self::vm_stack::VmStack; pub use self::vm_swap::VmSwap; pub use self::wchan::Wchan; pub use self::work_dir::WorkDir; pub use self::write_bytes::WriteBytes; use crate::column::Column; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::path::PathBuf; // --------------------------------------------------------------------------------------------------------------------- // ConfigColumnKind // --------------------------------------------------------------------------------------------------------------------- #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ConfigColumnKind { Ccgroup, Cgroup, Command, ContextSw, CpuTime, Docker, Eip, ElapsedTime, Empty, Env, Esp, FileName, Gid, GidFs, GidReal, GidSaved, Group, GroupFs, GroupReal, GroupSaved, MajFlt, MinFlt, MultiSlot, Nice, Pgid, Pid, Policy, Ppid, Priority, Processor, ReadBytes, RtPriority, SecContext, Separator, Session, ShdPnd, Slot, SigBlk, SigCgt, SigIgn, SigPnd, Ssb, StartTime, State, TcpPort, Threads, Tree, TreeSlot, Tty, UdpPort, Uid, UidFs, UidLogin, UidReal, UidSaved, UsageCpu, UsageMem, User, UserFs, UserLogin, UserReal, UserSaved, Username, VmData, VmExe, VmHwm, VmLib, VmLock, VmPeak, VmPin, VmPte, VmRss, VmSize, VmStack, VmSwap, Wchan, WorkDir, WriteBytes, } // --------------------------------------------------------------------------------------------------------------------- // gen_column // --------------------------------------------------------------------------------------------------------------------- pub fn gen_column( kind: &ConfigColumnKind, header: Option, _docker_path: &str, separator: &str, abbr_sid: bool, tree_symbols: &[String; 5], procfs: Option, ) -> Box { match kind { ConfigColumnKind::Ccgroup => Box::new(Ccgroup::new(header)), ConfigColumnKind::Cgroup => Box::new(Cgroup::new(header)), ConfigColumnKind::Command => Box::new(Command::new(header)), ConfigColumnKind::ContextSw => Box::new(ContextSw::new(header)), ConfigColumnKind::CpuTime => Box::new(CpuTime::new(header)), #[cfg(feature = "docker")] ConfigColumnKind::Docker => Box::new(Docker::new(header, _docker_path)), #[cfg(not(feature = "docker"))] ConfigColumnKind::Docker => Box::new(Empty::new()), ConfigColumnKind::Eip => Box::new(Eip::new(header)), ConfigColumnKind::ElapsedTime => Box::new(ElapsedTime::new(header)), ConfigColumnKind::Empty => Box::new(Empty::new()), ConfigColumnKind::Env => Box::new(Env::new(header, procfs)), ConfigColumnKind::Esp => Box::new(Esp::new(header)), ConfigColumnKind::FileName => Box::new(FileName::new(header)), ConfigColumnKind::Gid => Box::new(Gid::new(header, abbr_sid)), ConfigColumnKind::GidFs => Box::new(GidFs::new(header)), ConfigColumnKind::GidReal => Box::new(GidReal::new(header)), ConfigColumnKind::GidSaved => Box::new(GidSaved::new(header)), ConfigColumnKind::Group => Box::new(Group::new(header, abbr_sid)), ConfigColumnKind::GroupFs => Box::new(GroupFs::new(header)), ConfigColumnKind::GroupReal => Box::new(GroupReal::new(header)), ConfigColumnKind::GroupSaved => Box::new(GroupSaved::new(header)), ConfigColumnKind::MajFlt => Box::new(MajFlt::new(header)), ConfigColumnKind::MinFlt => Box::new(MinFlt::new(header)), ConfigColumnKind::MultiSlot => Box::new(MultiSlot::new()), ConfigColumnKind::Nice => Box::new(Nice::new(header)), ConfigColumnKind::Pgid => Box::new(Pgid::new(header)), ConfigColumnKind::Pid => Box::new(Pid::new(header)), ConfigColumnKind::Policy => Box::new(Policy::new(header)), ConfigColumnKind::Ppid => Box::new(Ppid::new(header)), ConfigColumnKind::Priority => Box::new(Priority::new(header)), ConfigColumnKind::Processor => Box::new(Processor::new(header)), ConfigColumnKind::ReadBytes => Box::new(ReadBytes::new(header)), ConfigColumnKind::RtPriority => Box::new(RtPriority::new(header)), ConfigColumnKind::SecContext => Box::new(SecContext::new(header, procfs)), ConfigColumnKind::Separator => Box::new(Separator::new(separator)), ConfigColumnKind::Session => Box::new(Session::new(header)), ConfigColumnKind::ShdPnd => Box::new(ShdPnd::new(header)), ConfigColumnKind::Slot => Box::new(Slot::new()), ConfigColumnKind::SigBlk => Box::new(SigBlk::new(header)), ConfigColumnKind::SigCgt => Box::new(SigCgt::new(header)), ConfigColumnKind::SigIgn => Box::new(SigIgn::new(header)), ConfigColumnKind::SigPnd => Box::new(SigPnd::new(header)), ConfigColumnKind::Ssb => Box::new(Ssb::new(header)), ConfigColumnKind::StartTime => Box::new(StartTime::new(header)), ConfigColumnKind::State => Box::new(State::new(header)), ConfigColumnKind::TcpPort => Box::new(TcpPort::new(header)), ConfigColumnKind::Threads => Box::new(Threads::new(header)), ConfigColumnKind::Tree => Box::new(Tree::new(tree_symbols)), ConfigColumnKind::TreeSlot => Box::new(TreeSlot::new()), ConfigColumnKind::Tty => Box::new(Tty::new(header)), ConfigColumnKind::UdpPort => Box::new(UdpPort::new(header)), ConfigColumnKind::Uid => Box::new(Uid::new(header, abbr_sid)), ConfigColumnKind::UidFs => Box::new(UidFs::new(header)), ConfigColumnKind::UidLogin => Box::new(UidLogin::new(header)), ConfigColumnKind::UidReal => Box::new(UidReal::new(header)), ConfigColumnKind::UidSaved => Box::new(UidSaved::new(header)), ConfigColumnKind::UsageCpu => Box::new(UsageCpu::new(header)), ConfigColumnKind::UsageMem => Box::new(UsageMem::new(header)), ConfigColumnKind::User => Box::new(User::new(header, abbr_sid)), ConfigColumnKind::UserFs => Box::new(UserFs::new(header)), ConfigColumnKind::UserLogin => Box::new(UserLogin::new(header)), ConfigColumnKind::UserReal => Box::new(UserReal::new(header)), ConfigColumnKind::UserSaved => Box::new(UserSaved::new(header)), ConfigColumnKind::Username => Box::new(User::new(header, abbr_sid)), ConfigColumnKind::VmData => Box::new(VmData::new(header)), ConfigColumnKind::VmExe => Box::new(VmExe::new(header)), ConfigColumnKind::VmHwm => Box::new(VmHwm::new(header)), ConfigColumnKind::VmLib => Box::new(VmLib::new(header)), ConfigColumnKind::VmLock => Box::new(VmLock::new(header)), ConfigColumnKind::VmPeak => Box::new(VmPeak::new(header)), ConfigColumnKind::VmPin => Box::new(VmPin::new(header)), ConfigColumnKind::VmPte => Box::new(VmPte::new(header)), ConfigColumnKind::VmRss => Box::new(VmRss::new(header)), ConfigColumnKind::VmSize => Box::new(VmSize::new(header)), ConfigColumnKind::VmStack => Box::new(VmStack::new(header)), ConfigColumnKind::VmSwap => Box::new(VmSwap::new(header)), ConfigColumnKind::Wchan => Box::new(Wchan::new(header)), ConfigColumnKind::WorkDir => Box::new(WorkDir::new(header, procfs)), ConfigColumnKind::WriteBytes => Box::new(WriteBytes::new(header)), } } // --------------------------------------------------------------------------------------------------------------------- // KIND_LIST // --------------------------------------------------------------------------------------------------------------------- pub static KIND_LIST: Lazy> = Lazy::new(|| { [ ( ConfigColumnKind::Ccgroup, ("Ccgroup", "Control group by compressed format"), ), (ConfigColumnKind::Cgroup, ("Cgroup", "Control group")), ( ConfigColumnKind::Command, ("Command", "Command with all arguments"), ), ( ConfigColumnKind::ContextSw, ("ContextSw", "Context switch count"), ), ( ConfigColumnKind::CpuTime, ("CpuTime", "Cumulative CPU time"), ), ( ConfigColumnKind::Docker, ("Docker", "Docker container name"), ), (ConfigColumnKind::Eip, ("Eip", "Instruction pointer")), ( ConfigColumnKind::ElapsedTime, ("ElapsedTime", "Elapsed time"), ), (ConfigColumnKind::Empty, ("Empty", "Empty")), (ConfigColumnKind::Env, ("Env", "Environment variables")), (ConfigColumnKind::Esp, ("Esp", "Stack pointer")), (ConfigColumnKind::FileName, ("FileName", "File name")), (ConfigColumnKind::Gid, ("Gid", "Group ID")), (ConfigColumnKind::GidFs, ("GidFs", "File system group ID")), (ConfigColumnKind::GidReal, ("GidReal", "Real group ID")), (ConfigColumnKind::GidSaved, ("GidSaved", "Saved group ID")), (ConfigColumnKind::Group, ("Group", "Group name")), ( ConfigColumnKind::GroupFs, ("GroupFs", "File system group name"), ), ( ConfigColumnKind::GroupReal, ("GroupReal", "Real group name"), ), ( ConfigColumnKind::GroupSaved, ("GroupSaved", "Saved group name"), ), ( ConfigColumnKind::MajFlt, ("MajFlt", "Major page fault count"), ), ( ConfigColumnKind::MinFlt, ("MinFlt", "Minor page fault count"), ), ( ConfigColumnKind::MultiSlot, ("MultiSlot", "Slot for `--insert` option"), ), (ConfigColumnKind::Nice, ("Nice", "Nice value")), (ConfigColumnKind::Pgid, ("Pgid", "Process group ID")), (ConfigColumnKind::Pid, ("Pid", "Process ID")), (ConfigColumnKind::Policy, ("Policy", "Scheduling policy")), (ConfigColumnKind::Ppid, ("Ppid", "Parent process ID")), (ConfigColumnKind::Priority, ("Priority", "Priority")), ( ConfigColumnKind::Processor, ("Processor", "Currently assigned processor"), ), ( ConfigColumnKind::ReadBytes, ("ReadBytes", "Read bytes from storage"), ), ( ConfigColumnKind::RtPriority, ("RtPriority", "Real-time priority"), ), ( ConfigColumnKind::SecContext, ("SecContext", "Security context"), ), ( ConfigColumnKind::Separator, ("Separator", "Show | for column separation"), ), (ConfigColumnKind::Session, ("Session", "Process Session ID")), ( ConfigColumnKind::ShdPnd, ("ShdPnd", "Pending signal mask for process"), ), ( ConfigColumnKind::Slot, ("Slot", "Slot for `--insert` option"), ), (ConfigColumnKind::SigBlk, ("SigBlk", "Blocked signal mask")), (ConfigColumnKind::SigCgt, ("SigCgt", "Caught signal mask")), (ConfigColumnKind::SigIgn, ("SigIgn", "Ignored signal mask")), ( ConfigColumnKind::SigPnd, ("SigPnd", "Pending signal mask for thread"), ), ( ConfigColumnKind::Ssb, ("Ssb", "Speculative store bypass status"), ), (ConfigColumnKind::StartTime, ("StartTime", "Starting time")), (ConfigColumnKind::State, ("State", "Process state")), (ConfigColumnKind::TcpPort, ("TcpPort", "Bound TCP ports")), (ConfigColumnKind::Threads, ("Threads", "Thread count")), ( ConfigColumnKind::TreeSlot, ("TreeSlot", "Slot for tree column"), ), (ConfigColumnKind::Tty, ("Tty", "Controlling TTY")), (ConfigColumnKind::UdpPort, ("UdpPort", "Bound UDP ports")), (ConfigColumnKind::Uid, ("Uid", "User ID")), (ConfigColumnKind::UidFs, ("UidFs", "File system user ID")), (ConfigColumnKind::UidLogin, ("UidLogin", "Login user ID")), (ConfigColumnKind::UidReal, ("UidReal", "Real user ID")), (ConfigColumnKind::UidSaved, ("UidSaved", "Saved user ID")), (ConfigColumnKind::UsageCpu, ("UsageCpu", "CPU utilization")), ( ConfigColumnKind::UsageMem, ("UsageMem", "Memory utilization"), ), (ConfigColumnKind::User, ("User", "User name")), ( ConfigColumnKind::UserFs, ("UserFs", "File system user name"), ), ( ConfigColumnKind::UserLogin, ("UserLogin", "Login user name"), ), (ConfigColumnKind::UserReal, ("UserReal", "Real user name")), ( ConfigColumnKind::UserSaved, ("UserSaved", "Saved user name"), ), (ConfigColumnKind::VmData, ("VmData", "Data size")), (ConfigColumnKind::VmExe, ("VmExe", "Text segments size")), (ConfigColumnKind::VmHwm, ("VmHwm", "Peak resident set size")), (ConfigColumnKind::VmLib, ("VmLib", "Library code size")), (ConfigColumnKind::VmLock, ("VmLock", "Locked memory size")), ( ConfigColumnKind::VmPeak, ("VmPeak", "Peak virtual memory size"), ), (ConfigColumnKind::VmPin, ("VmPin", "Pinned memory size")), ( ConfigColumnKind::VmPte, ("VmPte", "Page table entries size"), ), (ConfigColumnKind::VmRss, ("VmRss", "Resident set size")), (ConfigColumnKind::VmSize, ("VmSize", "Physical page size")), (ConfigColumnKind::VmStack, ("VmStack", "Stack size")), ( ConfigColumnKind::VmSwap, ("VmSwap", "Swapped-out virtual memory size"), ), ( ConfigColumnKind::Wchan, ("Wchan", "Process sleeping kernel function"), ), ( ConfigColumnKind::WorkDir, ("WorkDir", "Current working directory"), ), ( ConfigColumnKind::WriteBytes, ("WriteBytes", "Write bytes to storage"), ), ] .iter() .cloned() .collect() }); // --------------------------------------------------------------------------------------------------------------------- // CONFIG_DEFAULT // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_DEFAULT: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Tty" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false [[columns]] kind = "MultiSlot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_LARGE // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_LARGE: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false align = "Left" [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "State" style = "ByState" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Nice" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Tty" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmSize" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmRss" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "TcpPort" style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" max_width = 20 [[columns]] kind = "UdpPort" style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" max_width = 20 [[columns]] kind = "ReadBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "WriteBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Slot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "StartTime" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Docker" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true align = "Left" "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_ALL // --------------------------------------------------------------------------------------------------------------------- #[cfg(test)] pub static CONFIG_ALL: &str = r#" [[columns]] kind = "Ccgroup" style = "BrightRed" align = "Left" [[columns]] kind = "Cgroup" style = "BrightRed" align = "Left" [[columns]] kind = "Command" style = "BrightRed" align = "Left" [[columns]] kind = "ContextSw" style = "BrightRed" align = "Right" [[columns]] kind = "CpuTime" style = "BrightGreen" align = "Center" [[columns]] kind = "Docker" style = "BrightMagenta" [[columns]] kind = "Eip" style = "BrightYellow" [[columns]] kind = "ElapsedTime" style = "BrightYellow" [[columns]] kind = "Empty" style = "BrightYellow" [[columns]] kind = "Env" style = "BrightYellow" [[columns]] kind = "Esp" style = "BrightBlue" [[columns]] kind = "FileName" style = "BrightBlue" [[columns]] kind = "Gid" style = "White" [[columns]] kind = "GidFs" style = "White" [[columns]] kind = "GidReal" style = "White" [[columns]] kind = "GidSaved" style = "White" [[columns]] kind = "Group" style = "White" [[columns]] kind = "GroupFs" style = "White" [[columns]] kind = "GroupReal" style = "White" [[columns]] kind = "GroupSaved" style = "White" [[columns]] kind = "MajFlt" style = "BrightCyan" [[columns]] kind = "MinFlt" style = "BrightWhite" [[columns]] kind = "MultiSlot" style = "BrightWhite" [[columns]] kind = "Nice" style = "Red" [[columns]] kind = "Pgid" style = "Yellow" [[columns]] kind = "Pid" style = "Green" [[columns]] kind = "Policy" style = "Green" [[columns]] kind = "Ppid" style = "Yellow" [[columns]] kind = "Priority" style = "Blue" [[columns]] kind = "Processor" style = "Magenta" [[columns]] kind = "ReadBytes" style = "Cyan" [[columns]] kind = "RtPriority" style = "White" [[columns]] kind = "SecContext" style = "White" [[columns]] kind = "Separator" style = "White" [[columns]] kind = "Session" style = "Yellow" [[columns]] kind = "ShdPnd" style = "White" [[columns]] kind = "SigBlk" style = "White" [[columns]] kind = "SigCgt" style = "White" [[columns]] kind = "SigIgn" style = "White" [[columns]] kind = "SigPnd" style = "White" [[columns]] kind = "Ssb" style = "White" [[columns]] kind = "StartTime" style = "White" [[columns]] kind = "State" style = "White" [[columns]] kind = "TcpPort" style = "White" [[columns]] kind = "Threads" style = "White" [[columns]] kind = "TreeSlot" style = "BrightWhite" [[columns]] kind = "Tty" style = "White" [[columns]] kind = "UdpPort" style = "White" [[columns]] kind = "Uid" style = "White" [[columns]] kind = "UidFs" style = "White" [[columns]] kind = "UidLogin" style = "White" [[columns]] kind = "UidReal" style = "White" [[columns]] kind = "UidSaved" style = "White" [[columns]] kind = "UsageCpu" style = "White" [[columns]] kind = "UsageMem" style = "White" [[columns]] kind = "User" style = "White" [[columns]] kind = "UserFs" style = "White" [[columns]] kind = "UserLogin" style = "White" [[columns]] kind = "UserReal" style = "White" [[columns]] kind = "UserSaved" style = "White" [[columns]] kind = "VmData" style = "ByUnit" [[columns]] kind = "VmExe" style = "ByUnit" [[columns]] kind = "VmHwm" style = "ByUnit" [[columns]] kind = "VmLib" style = "ByUnit" [[columns]] kind = "VmLock" style = "ByUnit" [[columns]] kind = "VmPeak" style = "ByUnit" [[columns]] kind = "VmPin" style = "ByUnit" [[columns]] kind = "VmPte" style = "ByUnit" [[columns]] kind = "VmRss" style = "ByUnit" [[columns]] kind = "VmSize" style = "ByUnit" [[columns]] kind = "VmStack" style = "ByUnit" [[columns]] kind = "VmSwap" style = "ByUnit" [[columns]] kind = "Wchan" style = "White" [[columns]] kind = "WorkDir" style = "White" [[columns]] kind = "WriteBytes" style = "White" "#; procs-0.14.9/src/columns/os_macos.rs000064400000000000000000000430401046102023000154660ustar 00000000000000pub mod command; pub mod context_sw; pub mod cpu_time; #[cfg(feature = "docker")] pub mod docker; pub mod elapsed_time; pub mod empty; pub mod gid; pub mod gid_real; pub mod gid_saved; pub mod group; pub mod group_real; pub mod group_saved; pub mod maj_flt; pub mod min_flt; pub mod multi_slot; pub mod nice; pub mod pgid; pub mod pid; pub mod policy; pub mod ppid; pub mod priority; pub mod read_bytes; pub mod separator; pub mod session; pub mod slot; pub mod start_time; pub mod state; pub mod tcp_port; pub mod threads; pub mod tree; pub mod tree_slot; pub mod tty; pub mod udp_port; pub mod uid; pub mod uid_real; pub mod uid_saved; pub mod usage_cpu; pub mod usage_mem; pub mod user; pub mod user_real; pub mod user_saved; pub mod vm_rss; pub mod vm_size; pub mod write_bytes; pub use self::command::Command; pub use self::context_sw::ContextSw; pub use self::cpu_time::CpuTime; #[cfg(feature = "docker")] pub use self::docker::Docker; pub use self::elapsed_time::ElapsedTime; pub use self::empty::Empty; pub use self::gid::Gid; pub use self::gid_real::GidReal; pub use self::gid_saved::GidSaved; pub use self::group::Group; pub use self::group_real::GroupReal; pub use self::group_saved::GroupSaved; pub use self::maj_flt::MajFlt; pub use self::min_flt::MinFlt; pub use self::multi_slot::MultiSlot; pub use self::nice::Nice; pub use self::pgid::Pgid; pub use self::pid::Pid; pub use self::policy::Policy; pub use self::ppid::Ppid; pub use self::priority::Priority; pub use self::read_bytes::ReadBytes; pub use self::separator::Separator; pub use self::session::Session; pub use self::slot::Slot; pub use self::start_time::StartTime; pub use self::state::State; pub use self::tcp_port::TcpPort; pub use self::threads::Threads; pub use self::tree::Tree; pub use self::tree_slot::TreeSlot; pub use self::tty::Tty; pub use self::udp_port::UdpPort; pub use self::uid::Uid; pub use self::uid_real::UidReal; pub use self::uid_saved::UidSaved; pub use self::usage_cpu::UsageCpu; pub use self::usage_mem::UsageMem; pub use self::user::User; pub use self::user_real::UserReal; pub use self::user_saved::UserSaved; pub use self::vm_rss::VmRss; pub use self::vm_size::VmSize; pub use self::write_bytes::WriteBytes; use crate::column::Column; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::path::PathBuf; // --------------------------------------------------------------------------------------------------------------------- // ConfigColumnKind // --------------------------------------------------------------------------------------------------------------------- #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ConfigColumnKind { Command, ContextSw, CpuTime, Docker, ElapsedTime, Empty, Gid, GidReal, GidSaved, Group, GroupReal, GroupSaved, MajFlt, MinFlt, MultiSlot, Nice, Pgid, Pid, Policy, Ppid, Priority, ReadBytes, Separator, Session, Slot, StartTime, State, TcpPort, Threads, Tree, TreeSlot, Tty, UdpPort, Uid, UidReal, UidSaved, UsageCpu, UsageMem, User, UserReal, UserSaved, Username, VmRss, VmSize, WriteBytes, } // --------------------------------------------------------------------------------------------------------------------- // gen_column // --------------------------------------------------------------------------------------------------------------------- pub fn gen_column( kind: &ConfigColumnKind, header: Option, _docker_path: &str, separator: &str, abbr_sid: bool, tree_symbols: &[String; 5], _procfs: Option, ) -> Box { match kind { ConfigColumnKind::Command => Box::new(Command::new(header)), ConfigColumnKind::ContextSw => Box::new(ContextSw::new(header)), ConfigColumnKind::CpuTime => Box::new(CpuTime::new(header)), #[cfg(feature = "docker")] ConfigColumnKind::Docker => Box::new(Docker::new(header, _docker_path)), #[cfg(not(feature = "docker"))] ConfigColumnKind::Docker => Box::new(Empty::new()), ConfigColumnKind::ElapsedTime => Box::new(ElapsedTime::new(header)), ConfigColumnKind::Empty => Box::new(Empty::new()), ConfigColumnKind::Gid => Box::new(Gid::new(header, abbr_sid)), ConfigColumnKind::GidReal => Box::new(GidReal::new(header)), ConfigColumnKind::GidSaved => Box::new(GidSaved::new(header)), ConfigColumnKind::Group => Box::new(Group::new(header, abbr_sid)), ConfigColumnKind::GroupReal => Box::new(GroupReal::new(header)), ConfigColumnKind::GroupSaved => Box::new(GroupSaved::new(header)), ConfigColumnKind::MajFlt => Box::new(MajFlt::new(header)), ConfigColumnKind::MinFlt => Box::new(MinFlt::new(header)), ConfigColumnKind::MultiSlot => Box::new(MultiSlot::new()), ConfigColumnKind::Nice => Box::new(Nice::new(header)), ConfigColumnKind::Pgid => Box::new(Pgid::new(header)), ConfigColumnKind::Pid => Box::new(Pid::new(header)), ConfigColumnKind::Policy => Box::new(Policy::new(header)), ConfigColumnKind::Ppid => Box::new(Ppid::new(header)), ConfigColumnKind::Priority => Box::new(Priority::new(header)), ConfigColumnKind::ReadBytes => Box::new(ReadBytes::new(header)), ConfigColumnKind::Separator => Box::new(Separator::new(separator)), ConfigColumnKind::Session => Box::new(Session::new(header)), ConfigColumnKind::Slot => Box::new(Slot::new()), ConfigColumnKind::StartTime => Box::new(StartTime::new(header)), ConfigColumnKind::State => Box::new(State::new(header)), ConfigColumnKind::TcpPort => Box::new(TcpPort::new(header)), ConfigColumnKind::Threads => Box::new(Threads::new(header)), ConfigColumnKind::Tree => Box::new(Tree::new(tree_symbols)), ConfigColumnKind::TreeSlot => Box::new(TreeSlot::new()), ConfigColumnKind::Tty => Box::new(Tty::new(header)), ConfigColumnKind::UdpPort => Box::new(UdpPort::new(header)), ConfigColumnKind::Uid => Box::new(Uid::new(header, abbr_sid)), ConfigColumnKind::UidReal => Box::new(UidReal::new(header)), ConfigColumnKind::UidSaved => Box::new(UidSaved::new(header)), ConfigColumnKind::UsageCpu => Box::new(UsageCpu::new(header)), ConfigColumnKind::UsageMem => Box::new(UsageMem::new(header)), ConfigColumnKind::User => Box::new(User::new(header, abbr_sid)), ConfigColumnKind::UserReal => Box::new(UserReal::new(header)), ConfigColumnKind::UserSaved => Box::new(UserSaved::new(header)), ConfigColumnKind::Username => Box::new(User::new(header, abbr_sid)), ConfigColumnKind::VmRss => Box::new(VmRss::new(header)), ConfigColumnKind::VmSize => Box::new(VmSize::new(header)), ConfigColumnKind::WriteBytes => Box::new(WriteBytes::new(header)), } } // --------------------------------------------------------------------------------------------------------------------- // KIND_LIST // --------------------------------------------------------------------------------------------------------------------- pub static KIND_LIST: Lazy> = Lazy::new(|| { [ ( ConfigColumnKind::Command, ("Command", "Command with all arguments"), ), ( ConfigColumnKind::ContextSw, ("ContextSw", "Context switch count"), ), ( ConfigColumnKind::CpuTime, ("CpuTime", "Cumulative CPU time"), ), ( ConfigColumnKind::Docker, ("Docker", "Docker container name"), ), ( ConfigColumnKind::ElapsedTime, ("ElapsedTime", "Elapsed time"), ), (ConfigColumnKind::Empty, ("Empty", "Empty")), (ConfigColumnKind::Gid, ("Gid", "Group ID")), (ConfigColumnKind::GidReal, ("GidReal", "Real group ID")), (ConfigColumnKind::GidSaved, ("GidSaved", "Saved group ID")), (ConfigColumnKind::Group, ("Group", "Group name")), ( ConfigColumnKind::GroupReal, ("GroupReal", "Real group name"), ), ( ConfigColumnKind::GroupSaved, ("GroupSaved", "Saved group name"), ), ( ConfigColumnKind::MajFlt, ("MajFlt", "Major page fault count"), ), ( ConfigColumnKind::MinFlt, ("MinFlt", "Minor page fault count"), ), ( ConfigColumnKind::MultiSlot, ("MultiSlot", "Slot for `--insert` option"), ), (ConfigColumnKind::Nice, ("Nice", "Nice value")), (ConfigColumnKind::Pgid, ("Pgid", "Process group ID")), (ConfigColumnKind::Pid, ("Pid", "Process ID")), (ConfigColumnKind::Policy, ("Policy", "Scheduling policy")), (ConfigColumnKind::Ppid, ("Ppid", "Parent process ID")), (ConfigColumnKind::Priority, ("Priority", "Priority")), ( ConfigColumnKind::ReadBytes, ("ReadBytes", "Read bytes from storage"), ), ( ConfigColumnKind::Separator, ("Separator", "Show | for column separation"), ), (ConfigColumnKind::Session, ("Session", "Process Session ID")), ( ConfigColumnKind::Slot, ("Slot", "Slot for `--insert` option"), ), (ConfigColumnKind::StartTime, ("StartTime", "Starting time")), (ConfigColumnKind::State, ("State", "Process state")), (ConfigColumnKind::TcpPort, ("TcpPort", "Bound TCP ports")), (ConfigColumnKind::Threads, ("Threads", "Thread count")), ( ConfigColumnKind::TreeSlot, ("TreeSlot", "Slot for tree column"), ), (ConfigColumnKind::Tty, ("Tty", "Controlling TTY")), (ConfigColumnKind::UdpPort, ("UdpPort", "Bound UDP ports")), (ConfigColumnKind::Uid, ("Uid", "User ID")), (ConfigColumnKind::UidReal, ("UidReal", "Real user ID")), (ConfigColumnKind::UidSaved, ("UidSaved", "Saved user ID")), (ConfigColumnKind::UsageCpu, ("UsageCpu", "CPU utilization")), ( ConfigColumnKind::UsageMem, ("UsageMem", "Memory utilization"), ), (ConfigColumnKind::User, ("User", "User name")), (ConfigColumnKind::UserReal, ("UserReal", "Real user name")), ( ConfigColumnKind::UserSaved, ("UserSaved", "Saved user name"), ), (ConfigColumnKind::VmRss, ("VmRss", "Resident set size")), (ConfigColumnKind::VmSize, ("VmSize", "Physical page size")), ( ConfigColumnKind::WriteBytes, ("WriteBytes", "Write bytes to storage"), ), ] .iter() .cloned() .collect() }); // --------------------------------------------------------------------------------------------------------------------- // CONFIG_DEFAULT // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_DEFAULT: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Tty" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false [[columns]] kind = "MultiSlot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_LARGE // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_LARGE: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false align = "Left" [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "State" style = "ByState" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Nice" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Tty" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmSize" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmRss" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "TcpPort" style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" max_width = 20 [[columns]] kind = "UdpPort" style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" max_width = 20 [[columns]] kind = "ReadBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "WriteBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Slot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "StartTime" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Docker" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true align = "Left" "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_ALL // --------------------------------------------------------------------------------------------------------------------- #[cfg(test)] pub static CONFIG_ALL: &str = r#" [[columns]] kind = "Command" style = "BrightRed" align = "Left" [[columns]] kind = "ContextSw" style = "BrightRed" align = "Right" [[columns]] kind = "CpuTime" style = "BrightGreen" align = "Center" [[columns]] kind = "Docker" style = "BrightMagenta" [[columns]] kind = "ElapsedTime" style = "BrightYellow" [[columns]] kind = "Empty" style = "BrightYellow" [[columns]] kind = "Gid" style = "White" [[columns]] kind = "GidReal" style = "White" [[columns]] kind = "GidSaved" style = "White" [[columns]] kind = "Group" style = "White" [[columns]] kind = "GroupReal" style = "White" [[columns]] kind = "GroupSaved" style = "White" [[columns]] kind = "MajFlt" style = "BrightCyan" [[columns]] kind = "MinFlt" style = "BrightWhite" [[columns]] kind = "MultiSlot" style = "BrightWhite" [[columns]] kind = "Nice" style = "Red" [[columns]] kind = "Pgid" style = "Yellow" [[columns]] kind = "Pid" style = "Green" [[columns]] kind = "Policy" style = "Green" [[columns]] kind = "Ppid" style = "Yellow" [[columns]] kind = "Priority" style = "Blue" [[columns]] kind = "ReadBytes" style = "Cyan" [[columns]] kind = "Separator" style = "White" [[columns]] kind = "Session" style = "Yellow" [[columns]] kind = "StartTime" style = "White" [[columns]] kind = "State" style = "White" [[columns]] kind = "TcpPort" style = "White" [[columns]] kind = "Threads" style = "White" [[columns]] kind = "TreeSlot" style = "BrightWhite" [[columns]] kind = "Tty" style = "White" [[columns]] kind = "UdpPort" style = "White" [[columns]] kind = "Uid" style = "White" [[columns]] kind = "UidReal" style = "White" [[columns]] kind = "UidSaved" style = "White" [[columns]] kind = "UsageCpu" style = "White" [[columns]] kind = "UsageMem" style = "White" [[columns]] kind = "User" style = "White" [[columns]] kind = "UserReal" style = "White" [[columns]] kind = "UserSaved" style = "White" [[columns]] kind = "VmRss" style = "ByUnit" [[columns]] kind = "VmSize" style = "ByUnit" [[columns]] kind = "WriteBytes" style = "White" "#; procs-0.14.9/src/columns/os_windows.rs000064400000000000000000000316641046102023000160670ustar 00000000000000pub mod command; pub mod cpu_time; pub mod elapsed_time; pub mod empty; pub mod gid; pub mod group; pub mod maj_flt; pub mod multi_slot; pub mod pid; pub mod ppid; pub mod priority; pub mod read_bytes; pub mod separator; pub mod slot; pub mod start_time; pub mod tcp_port; pub mod threads; pub mod tree; pub mod tree_slot; pub mod uid; pub mod usage_cpu; pub mod usage_mem; pub mod user; pub mod vm_hwm; pub mod vm_peak; pub mod vm_pin; pub mod vm_rss; pub mod vm_size; pub mod vm_swap; pub mod write_bytes; pub use self::command::Command; pub use self::cpu_time::CpuTime; pub use self::elapsed_time::ElapsedTime; pub use self::empty::Empty; pub use self::gid::Gid; pub use self::group::Group; pub use self::maj_flt::MajFlt; pub use self::multi_slot::MultiSlot; pub use self::pid::Pid; pub use self::ppid::Ppid; pub use self::priority::Priority; pub use self::read_bytes::ReadBytes; pub use self::separator::Separator; pub use self::slot::Slot; pub use self::start_time::StartTime; pub use self::tcp_port::TcpPort; pub use self::threads::Threads; pub use self::tree::Tree; pub use self::tree_slot::TreeSlot; pub use self::uid::Uid; pub use self::usage_cpu::UsageCpu; pub use self::usage_mem::UsageMem; pub use self::user::User; pub use self::vm_hwm::VmHwm; pub use self::vm_peak::VmPeak; pub use self::vm_pin::VmPin; pub use self::vm_rss::VmRss; pub use self::vm_size::VmSize; pub use self::vm_swap::VmSwap; pub use self::write_bytes::WriteBytes; use crate::column::Column; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::path::PathBuf; // --------------------------------------------------------------------------------------------------------------------- // ConfigColumnKind // --------------------------------------------------------------------------------------------------------------------- #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ConfigColumnKind { Command, CpuTime, ElapsedTime, Empty, Gid, Group, MajFlt, MultiSlot, Pid, Ppid, Priority, ReadBytes, Separator, Slot, StartTime, TcpPort, Threads, Tree, TreeSlot, Uid, UsageCpu, UsageMem, User, VmHwm, VmPeak, VmPin, VmRss, VmSize, VmSwap, WriteBytes, } // --------------------------------------------------------------------------------------------------------------------- // gen_column // --------------------------------------------------------------------------------------------------------------------- pub fn gen_column( kind: &ConfigColumnKind, header: Option, _docker_path: &str, separator: &str, abbr_sid: bool, tree_symbols: &[String; 5], _procfs: Option, ) -> Box { match kind { ConfigColumnKind::Command => Box::new(Command::new(header)), ConfigColumnKind::CpuTime => Box::new(CpuTime::new(header)), ConfigColumnKind::ElapsedTime => Box::new(ElapsedTime::new(header)), ConfigColumnKind::Empty => Box::new(Empty::new()), ConfigColumnKind::Gid => Box::new(Gid::new(header, abbr_sid)), ConfigColumnKind::Group => Box::new(Group::new(header, abbr_sid)), ConfigColumnKind::MajFlt => Box::new(MajFlt::new(header)), ConfigColumnKind::MultiSlot => Box::new(MultiSlot::new()), ConfigColumnKind::Pid => Box::new(Pid::new(header)), ConfigColumnKind::Ppid => Box::new(Ppid::new(header)), ConfigColumnKind::Priority => Box::new(Priority::new(header)), ConfigColumnKind::ReadBytes => Box::new(ReadBytes::new(header)), ConfigColumnKind::Separator => Box::new(Separator::new(separator)), ConfigColumnKind::Slot => Box::new(Slot::new()), ConfigColumnKind::StartTime => Box::new(StartTime::new(header)), ConfigColumnKind::TcpPort => Box::new(TcpPort::new(header)), ConfigColumnKind::Threads => Box::new(Threads::new(header)), ConfigColumnKind::Tree => Box::new(Tree::new(tree_symbols)), ConfigColumnKind::TreeSlot => Box::new(TreeSlot::new()), ConfigColumnKind::Uid => Box::new(Uid::new(header, abbr_sid)), ConfigColumnKind::UsageCpu => Box::new(UsageCpu::new(header)), ConfigColumnKind::UsageMem => Box::new(UsageMem::new(header)), ConfigColumnKind::User => Box::new(User::new(header, abbr_sid)), ConfigColumnKind::VmHwm => Box::new(VmHwm::new(header)), ConfigColumnKind::VmPeak => Box::new(VmPeak::new(header)), ConfigColumnKind::VmPin => Box::new(VmPin::new(header)), ConfigColumnKind::VmRss => Box::new(VmRss::new(header)), ConfigColumnKind::VmSize => Box::new(VmSize::new(header)), ConfigColumnKind::VmSwap => Box::new(VmSwap::new(header)), ConfigColumnKind::WriteBytes => Box::new(WriteBytes::new(header)), } } // --------------------------------------------------------------------------------------------------------------------- // KIND_LIST // --------------------------------------------------------------------------------------------------------------------- pub static KIND_LIST: Lazy> = Lazy::new(|| { [ ( ConfigColumnKind::Command, ("Command", "Command with all arguments"), ), ( ConfigColumnKind::CpuTime, ("CpuTime", "Cumulative CPU time"), ), ( ConfigColumnKind::ElapsedTime, ("ElapsedTime", "Elapsed time"), ), (ConfigColumnKind::Empty, ("Empty", "Empty")), (ConfigColumnKind::Gid, ("Gid", "Group ID")), (ConfigColumnKind::Group, ("Group", "Group name")), ( ConfigColumnKind::MajFlt, ("MajFlt", "Major page fault count"), ), ( ConfigColumnKind::MultiSlot, ("MultiSlot", "Slot for `--insert` option"), ), (ConfigColumnKind::Pid, ("Pid", "Process ID")), (ConfigColumnKind::Ppid, ("Ppid", "Parent process ID")), (ConfigColumnKind::Priority, ("Priority", "Priority")), ( ConfigColumnKind::ReadBytes, ("ReadBytes", "Read bytes from storage"), ), ( ConfigColumnKind::Separator, ("Separator", "Show | for column separation"), ), ( ConfigColumnKind::Slot, ("Slot", "Slot for `--insert` option"), ), (ConfigColumnKind::StartTime, ("StartTime", "Starting time")), (ConfigColumnKind::TcpPort, ("TcpPort", "Bound TCP ports")), (ConfigColumnKind::Threads, ("Threads", "Thread count")), ( ConfigColumnKind::TreeSlot, ("TreeSlot", "Slot for tree column"), ), (ConfigColumnKind::Uid, ("Uid", "User ID")), (ConfigColumnKind::UsageCpu, ("UsageCpu", "CPU utilization")), ( ConfigColumnKind::UsageMem, ("UsageMem", "Memory utilization"), ), (ConfigColumnKind::User, ("User", "User name")), (ConfigColumnKind::VmHwm, ("VmHwm", "Peak resident set size")), ( ConfigColumnKind::VmPeak, ("VmPeak", "Peak virtual memory size"), ), (ConfigColumnKind::VmPin, ("VmPin", "Pinned memory size")), (ConfigColumnKind::VmRss, ("VmRss", "Resident set size")), (ConfigColumnKind::VmSize, ("VmSize", "Physical page size")), ( ConfigColumnKind::VmSwap, ("VmSwap", "Swapped-out virtual memory size"), ), ( ConfigColumnKind::WriteBytes, ("WriteBytes", "Write bytes to storage"), ), ] .iter() .cloned() .collect() }); // --------------------------------------------------------------------------------------------------------------------- // CONFIG_DEFAULT // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_DEFAULT: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false [[columns]] kind = "MultiSlot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_LARGE // --------------------------------------------------------------------------------------------------------------------- pub static CONFIG_LARGE: &str = r#" [[columns]] kind = "Pid" style = "BrightYellow|Yellow" numeric_search = true nonnumeric_search = false align = "Left" [[columns]] kind = "User" style = "BrightGreen|Green" numeric_search = false nonnumeric_search = true align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "UsageCpu" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "UsageMem" style = "ByPercentage" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmSize" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "VmRss" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "TcpPort" style = "BrightCyan|Cyan" numeric_search = true nonnumeric_search = false align = "Left" max_width = 20 [[columns]] kind = "ReadBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "WriteBytes" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Slot" style = "ByUnit" numeric_search = false nonnumeric_search = false align = "Right" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "CpuTime" style = "BrightCyan|Cyan" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "StartTime" style = "BrightMagenta|Magenta" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Separator" style = "White|BrightBlack" numeric_search = false nonnumeric_search = false align = "Left" [[columns]] kind = "Command" style = "BrightWhite|Black" numeric_search = false nonnumeric_search = true align = "Left" "#; // --------------------------------------------------------------------------------------------------------------------- // CONFIG_ALL // --------------------------------------------------------------------------------------------------------------------- #[cfg(test)] pub static CONFIG_ALL: &str = r#" [[columns]] kind = "Command" style = "BrightRed" align = "Left" [[columns]] kind = "CpuTime" style = "BrightGreen" align = "Center" [[columns]] kind = "ElapsedTime" style = "BrightYellow" [[columns]] kind = "Empty" style = "BrightYellow" [[columns]] kind = "Gid" style = "White" [[columns]] kind = "Group" style = "White" [[columns]] kind = "MajFlt" style = "BrightCyan" [[columns]] kind = "MultiSlot" style = "BrightWhite" [[columns]] kind = "Pid" style = "Green" [[columns]] kind = "Ppid" style = "Yellow" [[columns]] kind = "Priority" style = "Blue" [[columns]] kind = "ReadBytes" style = "Cyan" [[columns]] kind = "Separator" style = "White" [[columns]] kind = "StartTime" style = "White" [[columns]] kind = "TcpPort" style = "White" [[columns]] kind = "Threads" style = "White" [[columns]] kind = "TreeSlot" style = "BrightWhite" [[columns]] kind = "Uid" style = "White" [[columns]] kind = "UsageCpu" style = "White" [[columns]] kind = "UsageMem" style = "White" [[columns]] kind = "User" style = "White" [[columns]] kind = "VmHwm" style = "ByUnit" [[columns]] kind = "VmPeak" style = "ByUnit" [[columns]] kind = "VmPin" style = "ByUnit" [[columns]] kind = "VmRss" style = "ByUnit" [[columns]] kind = "VmSize" style = "ByUnit" [[columns]] kind = "VmSwap" style = "ByUnit" [[columns]] kind = "WriteBytes" style = "White" "#; procs-0.14.9/src/columns/pgid.rs000064400000000000000000000034751046102023000146160ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Pgid { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Pgid { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("PGID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Pgid { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().pgrp; let fmt_content = match proc.curr_proc { crate::process::ProcessTask::Process { .. } => format!("{raw_content}"), _ => format!("[{raw_content}]"), }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } #[cfg(target_os = "macos")] impl Column for Pgid { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.pbsd.pbi_pgid as i32; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } #[cfg(target_os = "freebsd")] impl Column for Pgid { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.pgid as i32; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } procs-0.14.9/src/columns/pid.rs000064400000000000000000000027011046102023000144360ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Pid { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Pid { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("PID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Pid { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.pid; let fmt_content = match proc.curr_proc { crate::process::ProcessTask::Process { .. } => format!("{raw_content}"), _ => format!("[{raw_content}]"), }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } #[cfg(not(any(target_os = "linux", target_os = "android")))] impl Column for Pid { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.pid; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } procs-0.14.9/src/columns/policy.rs000064400000000000000000000051101046102023000151560ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Policy { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Policy { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Policy")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(target_os = "linux")] impl Column for Policy { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = match proc.curr_proc.stat().policy.map(|x| x as i32) { Some(libc::SCHED_BATCH) => String::from("B"), Some(libc::SCHED_FIFO) => String::from("FF"), Some(libc::SCHED_IDLE) => String::from("IDL"), Some(libc::SCHED_OTHER) => String::from("TS"), Some(libc::SCHED_RR) => String::from("RR"), _ => String::new(), }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "android")] impl Column for Policy { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = match proc.curr_proc.stat().policy.map(|x| x as i32) { Some(libc::SCHED_NORMAL) => String::from("N"), Some(libc::SCHED_FIFO) => String::from("FF"), Some(libc::SCHED_RR) => String::from("RR"), Some(libc::SCHED_BATCH) => String::from("B"), Some(libc::SCHED_IDLE) => String::from("IDL"), Some(libc::SCHED_DEADLINE) => String::from("D"), _ => String::from(""), }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for Policy { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = match proc.curr_task.ptinfo.pti_policy { 1 => String::from("TS"), 2 => String::from("RR"), 4 => String::from("FF"), _ => String::from(""), }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/ppid.rs000064400000000000000000000016341046102023000146220ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Ppid { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Ppid { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Parent PID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for Ppid { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.ppid; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } procs-0.14.9/src/columns/priority.rs000064400000000000000000000046151046102023000155510ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Priority { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Priority { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Priority")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Priority { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().priority; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "macos")] impl Column for Priority { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.ptinfo.pti_priority as i64; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "windows")] impl Column for Priority { fn add(&mut self, proc: &ProcessInfo) { let raw_content = i64::from(proc.priority); let fmt_content = match raw_content { 0x0020 => String::from("Normal"), 0x0040 => String::from("Idle"), 0x0080 => String::from("High"), 0x0100 => String::from("Realtime"), 0x4000 => String::from("BelowNormal"), 0x8000 => String::from("AboveNormal"), _ => String::from("Unknown"), }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "freebsd")] impl Column for Priority { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.pri.level as i64 - 100; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } procs-0.14.9/src/columns/processor.rs000064400000000000000000000027361046102023000157110ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Processor { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Processor { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Processor")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Processor { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().processor.unwrap_or_default(); let fmt_content = if let Some(p) = proc.curr_proc.stat().processor { format!("{p}") } else { String::new() }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } #[cfg(target_os = "freebsd")] impl Column for Processor { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.lastcpu; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } procs-0.14.9/src/columns/read_bytes.rs000064400000000000000000000064011046102023000160040ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct ReadBytes { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl ReadBytes { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Read")); let unit = String::from("[B/s]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for ReadBytes { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if proc.curr_io.is_some() && proc.prev_io.is_some() { let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.curr_io.as_ref().unwrap().read_bytes - proc.prev_io.as_ref().unwrap().read_bytes) * 1000 / interval_ms; (bytify(io), io) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for ReadBytes { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if proc.curr_res.is_some() && proc.prev_res.is_some() { let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.curr_res.as_ref().unwrap().ri_diskio_bytesread - proc.prev_res.as_ref().unwrap().ri_diskio_bytesread) * 1000 / interval_ms; (bytify(io), io) } else { (String::from(""), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for ReadBytes { fn add(&mut self, proc: &ProcessInfo) { let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.disk_info.curr_read - proc.disk_info.prev_read) * 1000 / interval_ms; let raw_content = io; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for ReadBytes { fn add(&mut self, proc: &ProcessInfo) { // io block size: 128KB let block_size = 128 * 1024; let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.curr_proc.info.rusage.inblock as u64 - proc.prev_proc.info.rusage.inblock as u64) * block_size * 1000 / interval_ms; let raw_content = io; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/rt_priority.rs000064400000000000000000000021071046102023000162500ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct RtPriority { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl RtPriority { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("RT Priority")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for RtPriority { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().rt_priority.unwrap_or_default(); let fmt_content = if let Some(p) = proc.curr_proc.stat().rt_priority { format!("{p}") } else { String::new() }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/sec_context.rs000064400000000000000000000030541046102023000162020ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; #[cfg(any(target_os = "linux", target_os = "android"))] use std::io::Read; use std::path::PathBuf; pub struct SecContext { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, procfs: Option, } impl SecContext { pub fn new(header: Option, procfs: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Context")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, procfs, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for SecContext { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(proc) = crate::util::process_new(proc.pid, &self.procfs) { if let Ok(mut file) = proc.open_relative("attr/current") { let mut ret = String::new(); let _ = file.read_to_string(&mut ret); ret.trim_end_matches('\x00').to_string() } else { String::from("") } } else { String::from("") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/separator.rs000064400000000000000000000020371046102023000156640ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Separator { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, separator: String, } impl Separator { pub fn new(separator: &str) -> Self { let header = String::from(separator); let unit = String::from(separator); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, separator: String::from(separator), } } } impl Column for Separator { fn add(&mut self, proc: &ProcessInfo) { let raw_content = self.separator.clone(); let fmt_content = self.separator.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn sortable(&self) -> bool { false } column_default!(String); } procs-0.14.9/src/columns/session.rs000064400000000000000000000037401046102023000153510ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; #[cfg(target_os = "macos")] use nix::unistd::{self, Pid}; use std::cmp; use std::collections::HashMap; pub struct Session { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Session { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Session")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Session { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().session; let fmt_content = match proc.curr_proc { crate::process::ProcessTask::Process { .. } => format!("{raw_content}"), _ => format!("[{raw_content}]"), }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } #[cfg(target_os = "macos")] impl Column for Session { fn add(&mut self, proc: &ProcessInfo) { let sid = unistd::getsid(Some(Pid::from_raw(proc.pid))) .map(|x| x.as_raw()) .unwrap_or(0); let raw_content = sid; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } #[cfg(target_os = "freebsd")] impl Column for Session { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.sid; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i32); } procs-0.14.9/src/columns/shd_pnd.rs000064400000000000000000000027221046102023000153040ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct ShdPnd { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl ShdPnd { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("ShdPnd")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for ShdPnd { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let val = status.shdpnd; (format!("{val:016x}"), val) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for ShdPnd { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.siglist.0[0] as u64; let fmt_content = format!("{raw_content:016x}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/sig_blk.rs000064400000000000000000000027221046102023000152770ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct SigBlk { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl SigBlk { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("SigBlk")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for SigBlk { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let val = status.sigblk; (format!("{val:016x}"), val) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for SigBlk { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.sigmask.0[0] as u64; let fmt_content = format!("{raw_content:016x}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/sig_cgt.rs000064400000000000000000000027231046102023000153050ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct SigCgt { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl SigCgt { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("SigCgt")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for SigCgt { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let val = status.sigcgt; (format!("{val:016x}"), val) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for SigCgt { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.sigcatch.0[0] as u64; let fmt_content = format!("{raw_content:016x}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/sig_ign.rs000064400000000000000000000027241046102023000153060ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct SigIgn { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl SigIgn { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("SigIgn")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for SigIgn { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let val = status.sigign; (format!("{val:016x}"), val) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for SigIgn { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.sigignore.0[0] as u64; let fmt_content = format!("{raw_content:016x}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/sig_pnd.rs000064400000000000000000000020441046102023000153050ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct SigPnd { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl SigPnd { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("SigPnd")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for SigPnd { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let val = status.sigpnd; (format!("{val:016x}"), val) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/slot.rs000064400000000000000000000015361046102023000146500ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Slot { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Slot { pub fn new() -> Self { let header = String::new(); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for Slot { fn add(&mut self, proc: &ProcessInfo) { let raw_content = String::new(); let fmt_content = String::new(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/ssb.rs000064400000000000000000000022541046102023000144540ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Ssb { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Ssb { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Speculative Store Bypass")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for Ssb { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref curr_status) = proc.curr_status { if let Some(ref val) = curr_status.speculation_store_bypass { val.clone() } else { String::new() } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/start_time.rs000064400000000000000000000064001046102023000160350ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; #[cfg(not(target_os = "windows"))] use chrono::offset::TimeZone; #[cfg(any(target_os = "linux", target_os = "android"))] use chrono::Duration; use chrono::{DateTime, Local}; #[cfg(any(target_os = "linux", target_os = "android"))] use once_cell::sync::Lazy; use std::cmp; use std::collections::HashMap; #[cfg(any(target_os = "linux", target_os = "android"))] static TICKS_PER_SECOND: Lazy = Lazy::new(procfs::ticks_per_second); pub struct StartTime { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap>, width: usize, #[cfg(any(target_os = "linux", target_os = "android"))] boot_time: DateTime, } impl StartTime { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Start")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, #[cfg(any(target_os = "linux", target_os = "android"))] boot_time: procfs::boot_time().unwrap_or_else(|_| Local.timestamp_opt(0, 0).unwrap()), } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for StartTime { fn add(&mut self, proc: &ProcessInfo) { let starttime = proc.curr_proc.stat().starttime; let seconds_since_boot = starttime as f32 / *TICKS_PER_SECOND as f32; let raw_content = self.boot_time + Duration::try_milliseconds((seconds_since_boot * 1000.0) as i64).unwrap_or_default(); let fmt_content = format!("{}", raw_content.format("%Y/%m/%d %H:%M")); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(DateTime); } #[cfg(target_os = "macos")] impl Column for StartTime { fn add(&mut self, proc: &ProcessInfo) { let start_time = Local .timestamp_opt(proc.curr_task.pbsd.pbi_start_tvsec as i64, 0) .unwrap(); let raw_content = start_time; let fmt_content = format!("{}", start_time.format("%Y/%m/%d %H:%M")); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(DateTime); } #[cfg(target_os = "windows")] impl Column for StartTime { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.start_time; let fmt_content = format!("{}", proc.start_time.format("%Y/%m/%d %H:%M")); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(DateTime); } #[cfg(target_os = "freebsd")] impl Column for StartTime { fn add(&mut self, proc: &ProcessInfo) { let start_time = Local .timestamp_opt(proc.curr_proc.info.start.sec as i64, 0) .unwrap(); let raw_content = start_time; let fmt_content = format!("{}", start_time.format("%Y/%m/%d %H:%M")); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(DateTime); } procs-0.14.9/src/columns/state.rs000064400000000000000000000106111046102023000150010ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct State { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl State { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("State")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for State { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = format!("{}", proc.curr_proc.stat().state); let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for State { fn add(&mut self, proc: &ProcessInfo) { let mut state = 7; for t in &proc.curr_threads { let s = match t.pth_run_state { 1 => 1, // TH_STATE_RUNNING 2 => 5, // TH_STATE_STOPPED 3 => { if t.pth_sleep_time > 20 { 4 } else { 3 } } // TH_STATE_WAITING 4 => 2, // TH_STATE_UNINTERRUPTIBLE 5 => 6, // TH_STATE_HALTED _ => 7, }; state = cmp::min(s, state); } let state = match state { 0 => "", 1 => "R", 2 => "U", 3 => "S", 4 => "I", 5 => "T", 6 => "H", _ => "?", }; let fmt_content = state.to_string(); let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for State { fn add(&mut self, proc: &ProcessInfo) { let info = &proc.curr_proc.info; let flag = info.flag; let tdflags = info.tdflags; let cr_flags = info.cr_flags; let kiflag = info.kiflag; let mut state = match info.stat { libc::SSTOP => "T", libc::SSLEEP => { if (tdflags & libc::TDF_SINTR as i64) != 0 { if info.slptime >= 20 { "I" } else { "S" } } else { "D" } } libc::SRUN | libc::SIDL => "R", libc::SWAIT => "W", libc::SLOCK => "L", libc::SZOMB => "Z", _ => "?", } .to_string(); if (flag & libc::P_INMEM as i64) == 0 { state.push_str("W"); } if info.nice < libc::NZERO as i8 || info.pri.class == bsd_kvm_sys::PRI_REALTIME as u8 { state.push_str("<"); } if info.nice > libc::NZERO as i8 || info.pri.class == bsd_kvm_sys::PRI_IDLE as u8 { state.push_str("N"); } if (flag & libc::P_TRACED as i64) != 0 { state.push_str("X"); } if (flag & libc::P_WEXIT as i64) != 0 && info.stat != libc::SZOMB as std::os::raw::c_char { state.push_str("E"); } if (flag & libc::P_PPWAIT as i64) != 0 { state.push_str("V"); } if (flag & libc::P_SYSTEM as i64) != 0 || info.lock > 0 { state.push_str("L"); } if (cr_flags & libc::KI_CRF_CAPABILITY_MODE as u32) != 0 { state.push_str("C"); } if (kiflag & libc::KI_SLEADER as i64) != 0 { state.push_str("s"); } if (flag & libc::P_CONTROLT as i64) != 0 && info.pgid == info.tpgid { state.push_str("+"); } if (flag & libc::P_JAILED as i64) != 0 { state.push_str("J"); } let fmt_content = state; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/tcp_port.rs000064400000000000000000000256451046102023000155300ustar 00000000000000use crate::process::ProcessInfo; use crate::Column; #[cfg(target_os = "macos")] use libproc::libproc::net_info::TcpSIState; #[cfg(any(target_os = "linux", target_os = "android"))] use procfs::net::{TcpNetEntry, TcpState}; #[cfg(any(target_os = "linux", target_os = "android"))] use procfs::process::FDTarget; use std::cmp; use std::collections::HashMap; #[cfg(target_os = "windows")] use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; #[cfg(target_os = "windows")] use windows_sys::Win32::NetworkManagement::IpHelper::{GetTcpTable2, GetTcp6Table2, MIB_TCP_STATE, MIB_TCPTABLE2, MIB_TCP_STATE_LISTEN, MIB_TCP6TABLE2}; #[cfg(target_os = "windows")] use windows_sys::Win32::Foundation::{ERROR_INSUFFICIENT_BUFFER, NO_ERROR}; #[cfg(target_os = "windows")] use windows_sys::Win32::Networking::WinSock::{ntohl, ntohs}; pub struct TcpPort { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))] tcp_entry: Vec, #[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))] tcp6_entry: Vec, } impl TcpPort { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("TCP")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, #[cfg(any(target_os = "linux", target_os = "android"))] tcp_entry: procfs::net::tcp().unwrap_or_default(), #[cfg(any(target_os = "linux", target_os = "android"))] tcp6_entry: procfs::net::tcp6().unwrap_or_default(), #[cfg(target_os = "windows")] tcp_entry: get_tcp_entry_list().unwrap_or_default(), #[cfg(target_os = "windows")] tcp6_entry: get_tcp6_entry_list().unwrap_or_default(), } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for TcpPort { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(fds) = proc.curr_proc.fd() { let mut socks = Vec::new(); for fd in fds { if let FDTarget::Socket(x) = fd.target { socks.push(x) } } let mut ports = Vec::new(); for sock in &socks { let mut tcp_iter = self.tcp_entry.iter().chain(self.tcp6_entry.iter()); let entry = tcp_iter.find(|&x| x.inode == *sock); if let Some(entry) = entry { if entry.state == TcpState::Listen { ports.push(entry.local_address.port()); } } } ports.sort_unstable(); ports.dedup(); format!("{ports:?}") } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn find_exact(&self, pid: i32, keyword: &str, _content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { let content = content.replace(['[', ']'], ""); let content = content.split(','); for c in content { if c == keyword { return true; } } false } else { false } } crate::column_default_display_header!(); crate::column_default_display_unit!(); crate::column_default_display_content!(); crate::column_default_find_partial!(); crate::column_default_sorted_pid!(String); crate::column_default_apply_visible!(); crate::column_default_reset_width!(); crate::column_default_update_width!(); crate::column_default_get_width!(); } #[cfg(target_os = "macos")] impl Column for TcpPort { fn add(&mut self, proc: &ProcessInfo) { let mut ports = Vec::new(); for tcp in &proc.curr_tcps { if let TcpSIState::Listen = tcp.tcpsi_state.into() { let port = crate::util::change_endian(tcp.tcpsi_ini.insi_lport as u32) >> 16; ports.push(port); } } ports.sort(); ports.dedup(); let fmt_content = format!("{:?}", ports); let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn find_exact(&self, pid: i32, keyword: &str, _content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { let content = content.replace(['[', ']'], ""); let content = content.split(','); for c in content { if c == keyword { return true; } } false } else { false } } crate::column_default_display_header!(); crate::column_default_display_unit!(); crate::column_default_display_content!(); crate::column_default_find_partial!(); crate::column_default_sorted_pid!(String); crate::column_default_apply_visible!(); crate::column_default_reset_width!(); crate::column_default_update_width!(); crate::column_default_get_width!(); } #[cfg(target_os = "windows")] impl Column for TcpPort { fn add(&mut self, proc: &ProcessInfo) { let mut ports: Vec<_> = self .tcp_entry .iter() .chain(self.tcp6_entry.iter()) .filter(|entry| entry.state == MIB_TCP_STATE_LISTEN && entry.pid == proc.pid as u32) .map(|entry| entry.local_address.port()) .collect(); ports.sort_unstable(); ports.dedup(); let fmt_content = format!("{:?}", ports); let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn find_exact(&self, pid: i32, keyword: &str, _content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { let content = content.replace(['[', ']'], ""); let content = content.split(','); for c in content { if c == keyword { return true; } } false } else { false } } crate::column_default_display_header!(); crate::column_default_display_unit!(); crate::column_default_display_content!(); crate::column_default_find_partial!(); crate::column_default_sorted_pid!(String); crate::column_default_apply_visible!(); crate::column_default_reset_width!(); crate::column_default_update_width!(); crate::column_default_get_width!(); } #[derive(Debug, Clone)] #[cfg(target_os = "windows")] pub struct TcpNetEntry { pub local_address: SocketAddr, #[allow(dead_code)] pub remote_address: SocketAddr, pub state: MIB_TCP_STATE, pub pid: u32, } #[cfg(target_os = "windows")] fn get_tcp_entry_list() -> Result, anyhow::Error> { let mut entry_list = Vec::new(); let mut buffer_size = 0; let ret = unsafe { GetTcpTable2(std::ptr::null_mut(), &mut buffer_size, 0) }; if ret != ERROR_INSUFFICIENT_BUFFER { return Err(std::io::Error::last_os_error().into()); } let mut buffer = vec![0u8; buffer_size as usize]; let ret = unsafe { GetTcpTable2( buffer.as_mut_ptr() as *mut MIB_TCPTABLE2, &mut buffer_size, 0, ) }; if ret != NO_ERROR { return Err(std::io::Error::last_os_error().into()); } let tcp_table = unsafe { &*(buffer.as_ptr() as *const MIB_TCPTABLE2) }; for i in 0..tcp_table.dwNumEntries { let entry = unsafe { &*tcp_table.table.as_ptr().add(i as usize) }; entry_list.push(TcpNetEntry { local_address: SocketAddr::V4(SocketAddrV4::new( Ipv4Addr::from(unsafe { ntohl(entry.dwLocalAddr) }), unsafe { ntohs(entry.dwLocalPort as u16) }, )), remote_address: SocketAddr::V4(SocketAddrV4::new( Ipv4Addr::from(entry.dwRemoteAddr), unsafe { ntohs(entry.dwRemotePort as u16) }, )), pid: entry.dwOwningPid, state: entry.dwState as i32, }); } Ok(entry_list) } #[cfg(target_os = "windows")] fn get_tcp6_entry_list() -> Result, anyhow::Error> { let mut entry_list = Vec::new(); let mut buffer_size = 0; let ret = unsafe { GetTcp6Table2(std::ptr::null_mut(), &mut buffer_size, 0) }; if ret != ERROR_INSUFFICIENT_BUFFER { return Err(std::io::Error::last_os_error().into()); } let mut buffer = vec![0u8; buffer_size as usize]; let ret = unsafe { GetTcp6Table2( buffer.as_mut_ptr() as *mut MIB_TCP6TABLE2, &mut buffer_size, 0, ) }; if ret != NO_ERROR { return Err(std::io::Error::last_os_error().into()); } let tcp_table = unsafe { &*(buffer.as_ptr() as *const MIB_TCP6TABLE2) }; for i in 0..tcp_table.dwNumEntries { let entry = unsafe { *tcp_table.table.as_ptr().add(i as usize) }; entry_list.push(TcpNetEntry { local_address: SocketAddr::V6(SocketAddrV6::new( Ipv6Addr::from(u128::from_be_bytes(unsafe { entry.LocalAddr.u.Byte })), unsafe { ntohs(entry.dwLocalPort as u16) }, 0, entry.dwLocalScopeId, )), remote_address: SocketAddr::V6(SocketAddrV6::new( Ipv6Addr::from(u128::from_be_bytes(unsafe { entry.RemoteAddr.u.Byte })), unsafe { ntohs(entry.dwRemotePort as u16) }, 0, entry.dwRemoteScopeId, )), pid: entry.dwOwningPid, state: entry.State, }); } Ok(entry_list) } #[cfg(test)] #[cfg(target_os = "windows")] mod tests { use std::net::TcpListener; use windows_sys::Win32::NetworkManagement::IpHelper::MIB_TCP_STATE_LISTEN; use super::TcpPort; #[test] fn test_tcp_port() { assert!(test_ip_port("127.0.0.1:0")); assert!(test_ip_port("0.0.0.0:0")); assert!(test_ip_port("[::1]:0")); assert!(test_ip_port("[::]:0")); } fn test_ip_port(address: &str) -> bool { let listener = TcpListener::bind(address).unwrap(); let tcp_port = TcpPort::new(None); let found = tcp_port .tcp_entry .iter() .chain(tcp_port.tcp6_entry.iter()) .find(|entry| { entry.state == MIB_TCP_STATE_LISTEN && entry.local_address == listener.local_addr().unwrap() }); found.is_some() } } procs-0.14.9/src/columns/threads.rs000064400000000000000000000040741046102023000153210ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Threads { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Threads { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Threads")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Threads { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().num_threads; let fmt_content = format!("{raw_content}"); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "macos")] impl Column for Threads { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.ptinfo.pti_threadnum as i64; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "windows")] impl Column for Threads { fn add(&mut self, proc: &ProcessInfo) { let raw_content = i64::from(proc.thread); let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } #[cfg(target_os = "freebsd")] impl Column for Threads { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.numthreads as i64; let fmt_content = format!("{}", raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(i64); } procs-0.14.9/src/columns/tree.rs000064400000000000000000000213221046102023000146210ustar 00000000000000use crate::process::ProcessInfo; use crate::Column; use std::cmp; use std::collections::HashMap; pub struct Tree { header: String, unit: String, width: usize, tree: HashMap>, rev_tree: HashMap, symbols: [String; 5], } impl Tree { pub fn new(symbols: &[String; 5]) -> Self { let header = String::new(); let unit = String::new(); Self { width: 0, header, unit, tree: HashMap::new(), rev_tree: HashMap::new(), symbols: symbols.clone(), } } } impl Column for Tree { fn add(&mut self, proc: &ProcessInfo) { if let Some(node) = self.tree.get_mut(&proc.ppid) { node.push(proc.pid); node.sort_unstable(); } else { self.tree.insert(proc.ppid, vec![proc.pid]); } self.rev_tree.insert(proc.pid, proc.ppid); } fn display_header( &self, align: &crate::config::ConfigColumnAlign, _order: Option, _config: &crate::config::Config, ) -> String { crate::util::adjust(&self.header, self.width, align) } fn display_content( &self, pid: i32, align: &crate::config::ConfigColumnAlign, ) -> Option { fn gen_root( tree: &HashMap>, rev_tree: &HashMap, symbols: &[String; 5], pid: i32, mut string: String, ) -> String { if let Some(ppid) = rev_tree.get(&pid) { if *ppid == pid { string } else if let Some(pppid) = rev_tree.get(ppid) { let brother = tree.get(pppid).unwrap(); let is_last = brother.binary_search(ppid).unwrap() == brother.len() - 1; if is_last { string.push(' '); } else { string.push_str(&symbols[0]); } gen_root(tree, rev_tree, symbols, *ppid, string) } else { string } } else { string } } if let Some(ppid) = self.rev_tree.get(&pid) { let root = gen_root( &self.tree, &self.rev_tree, &self.symbols, pid, String::new(), ); let root: String = root.chars().rev().collect(); let brother = &self.tree[ppid]; let is_last = brother.binary_search(&pid).unwrap() == brother.len() - 1; let has_child = self.tree.contains_key(&pid); let parent_connector = if is_last { &self.symbols[4] } else { &self.symbols[3] }; let child_connector = if has_child { &self.symbols[2] } else { &self.symbols[1] }; let string = format!( "{}{}{}{}", root, parent_connector, child_connector, self.symbols[1].repeat(self.width - root.chars().count() - 2) ); Some(crate::util::adjust(&string, self.width, align)) } else { None } } fn find_partial(&self, _pid: i32, _keyword: &str, _content_to_lowercase: bool) -> bool { false } fn find_exact(&self, _pid: i32, _keyword: &str, _content_to_lowercase: bool) -> bool { false } fn sorted_pid(&self, _order: &crate::config::ConfigSortOrder) -> Vec { let mut root_pids = Vec::new(); for p in self.rev_tree.values() { if !self.rev_tree.contains_key(p) { root_pids.push(*p); } else if let Some(ppid) = self.rev_tree.get(p) { if *ppid == *p { root_pids.push(*p); } } } root_pids.sort_unstable(); root_pids.dedup(); fn push_pid(tree: &HashMap>, mut pids: Vec, pid: i32) -> Vec { if let Some(leafs) = tree.get(&pid) { for p in leafs { pids.push(*p); if pid != *p { pids = push_pid(tree, pids, *p); } } } pids } let mut pids = Vec::new(); for r in &root_pids { pids = push_pid(&self.tree, pids, *r); } pids } fn apply_visible(&mut self, visible_pids: &[i32]) { let mut remove_pids = Vec::new(); for k in self.rev_tree.keys() { if !visible_pids.contains(k) { remove_pids.push(*k); } } for pid in remove_pids { self.rev_tree.remove(&pid); for x in self.tree.values_mut() { if let Ok(i) = x.binary_search(&pid) { x.remove(i); } } } } fn reset_width( &mut self, _order: Option, _config: &crate::config::Config, _max_width: Option, _min_width: Option, ) { self.width = 0; } fn update_width(&mut self, pid: i32, _max_width: Option) { fn get_depth(rev_tree: &HashMap, pid: i32, depth: i32) -> i32 { if let Some(ppid) = rev_tree.get(&pid) { if *ppid == pid { depth } else { get_depth(rev_tree, *ppid, depth + 1) } } else { depth } } let depth = get_depth(&self.rev_tree, pid, 0) as usize; self.width = cmp::max(depth + 4, self.width); } crate::column_default_display_unit!(); crate::column_default_get_width!(); } #[cfg(test)] #[cfg(any(target_os = "linux", target_os = "android"))] mod tests { use super::*; use crate::process::ProcessTask; use procfs::process::Process; use std::time::Duration; #[test] fn test_tree() { let mut tree = Tree::new(&[ String::from("│"), String::from("─"), String::from("┬"), String::from("├"), String::from("└"), ]); let curr_proc = ProcessTask::Process { stat: Process::myself().unwrap().stat().unwrap(), proc: Process::myself().unwrap(), owner: Process::myself().unwrap().uid().unwrap(), }; let prev_stat = Process::myself().unwrap().stat().unwrap(); let p0 = ProcessInfo { pid: 0, ppid: 0, curr_proc, prev_stat, curr_io: None, prev_io: None, curr_status: None, interval: Duration::new(0, 0), }; let curr_proc = ProcessTask::Process { stat: Process::myself().unwrap().stat().unwrap(), proc: Process::myself().unwrap(), owner: Process::myself().unwrap().uid().unwrap(), }; let prev_stat = Process::myself().unwrap().stat().unwrap(); let p1 = ProcessInfo { pid: 1, ppid: 0, curr_proc, prev_stat, curr_io: None, prev_io: None, curr_status: None, interval: Duration::new(0, 0), }; let curr_proc = ProcessTask::Process { stat: Process::myself().unwrap().stat().unwrap(), proc: Process::myself().unwrap(), owner: Process::myself().unwrap().uid().unwrap(), }; let prev_stat = Process::myself().unwrap().stat().unwrap(); let p2 = ProcessInfo { pid: 2, ppid: 1, curr_proc, prev_stat, curr_io: None, prev_io: None, curr_status: None, interval: Duration::new(0, 0), }; tree.add(&p0); tree.add(&p1); tree.add(&p2); tree.update_width(0, None); tree.update_width(1, None); tree.update_width(2, None); assert_eq!( tree.display_content(0, &crate::config::ConfigColumnAlign::Left) .unwrap(), String::from("├┬────") ); assert_eq!( tree.display_content(1, &crate::config::ConfigColumnAlign::Left) .unwrap(), String::from("│└┬───") ); assert_eq!( tree.display_content(2, &crate::config::ConfigColumnAlign::Left) .unwrap(), String::from("│ └───") ); } } procs-0.14.9/src/columns/tree_slot.rs000064400000000000000000000015521046102023000156650ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct TreeSlot { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl TreeSlot { pub fn new() -> Self { let header = String::new(); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for TreeSlot { fn add(&mut self, proc: &ProcessInfo) { let raw_content = String::new(); let fmt_content = String::new(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/tty.rs000064400000000000000000000053311046102023000145040ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Tty { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Tty { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("TTY")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Tty { fn add(&mut self, proc: &ProcessInfo) { let (major, minor) = proc.curr_proc.stat().tty_nr(); let fmt_content = if major == 136 { format!("pts/{minor}") } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for Tty { fn add(&mut self, proc: &ProcessInfo) { let dev = proc.curr_task.pbsd.e_tdev; let major = (dev >> 24) & 0xff; let minor = dev & 0xffffff; let fmt_content = if major == 16 { format!("s{:03}", minor) } else { String::from("") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for Tty { fn add(&mut self, proc: &ProcessInfo) { let dev = proc.curr_proc.info.tdev; let mut buf = [0u8; 256]; let name = std::ffi::CString::new("kern.devname").unwrap(); let mut buf_size = std::mem::size_of::<[u8; 256]>(); let buf_ptr = buf.as_mut_ptr(); let dev_size = std::mem::size_of::(); let dev_ptr: *const u64 = &dev; unsafe { libc::sysctlbyname( name.as_ptr(), buf_ptr as *mut libc::c_void, &mut buf_size, dev_ptr as *const libc::c_void, dev_size, ); } let fmt_content = if let Ok(devname) = std::ffi::CStr::from_bytes_until_nul(&buf) { devname.to_string_lossy().into_owned() } else { String::from("") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/udp_port.rs000064400000000000000000000107621046102023000155240ustar 00000000000000use crate::process::ProcessInfo; use crate::Column; #[cfg(any(target_os = "linux", target_os = "android"))] use procfs::net::UdpNetEntry; #[cfg(any(target_os = "linux", target_os = "android"))] use procfs::process::FDTarget; use std::cmp; use std::collections::HashMap; pub struct UdpPort { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[cfg(any(target_os = "linux", target_os = "android"))] udp_entry: Vec, #[cfg(any(target_os = "linux", target_os = "android"))] udp6_entry: Vec, } impl UdpPort { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("UDP")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, #[cfg(any(target_os = "linux", target_os = "android"))] udp_entry: procfs::net::udp().unwrap_or_default(), #[cfg(any(target_os = "linux", target_os = "android"))] udp6_entry: procfs::net::udp6().unwrap_or_default(), } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UdpPort { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(fds) = proc.curr_proc.fd() { let mut socks = Vec::new(); for fd in fds { if let FDTarget::Socket(x) = fd.target { socks.push(x) } } let mut ports = Vec::new(); for sock in &socks { let mut udp_iter = self.udp_entry.iter().chain(self.udp6_entry.iter()); let entry = udp_iter.find(|&x| x.inode == *sock); if let Some(entry) = entry { ports.push(entry.local_address.port()); } } ports.sort_unstable(); ports.dedup(); format!("{ports:?}") } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn find_exact(&self, pid: i32, keyword: &str, _content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { let content = content.replace(['[', ']'], ""); let content = content.split(','); for c in content { if c == keyword { return true; } } false } else { false } } crate::column_default_display_header!(); crate::column_default_display_unit!(); crate::column_default_display_content!(); crate::column_default_find_partial!(); crate::column_default_sorted_pid!(String); crate::column_default_apply_visible!(); crate::column_default_reset_width!(); crate::column_default_update_width!(); crate::column_default_get_width!(); } #[cfg(target_os = "macos")] impl Column for UdpPort { fn add(&mut self, proc: &ProcessInfo) { let mut ports = Vec::new(); for udp in &proc.curr_udps { let port = crate::util::change_endian(udp.insi_lport as u32) >> 16; if port != 0 { ports.push(port); } } ports.sort(); ports.dedup(); let fmt_content = format!("{:?}", ports); let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } fn find_exact(&self, pid: i32, keyword: &str, _content_to_lowercase: bool) -> bool { if let Some(content) = self.fmt_contents.get(&pid) { let content = content.replace(['[', ']'], ""); let content = content.split(','); for c in content { if c == keyword { return true; } } false } else { false } } crate::column_default_display_header!(); crate::column_default_display_unit!(); crate::column_default_display_content!(); crate::column_default_find_partial!(); crate::column_default_sorted_pid!(String); crate::column_default_apply_visible!(); crate::column_default_reset_width!(); crate::column_default_update_width!(); crate::column_default_get_width!(); } procs-0.14.9/src/columns/uid.rs000064400000000000000000000044731046102023000144530ustar 00000000000000use crate::process::ProcessInfo; #[cfg(target_os = "windows")] use crate::util::format_sid; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Uid { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[allow(dead_code)] abbr_sid: bool, } impl Uid { pub fn new(header: Option, abbr_sid: bool) -> Self { let header = header.unwrap_or_else(|| String::from("UID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, abbr_sid, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Uid { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let uid = status.euid; (format!("{uid}"), uid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for Uid { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_task.pbsd.pbi_uid; let fmt_content = format!("{}", uid); let raw_content = uid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "windows")] impl Column for Uid { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = format_sid(&proc.user.sid, self.abbr_sid); let raw_content = proc.user.sid[proc.user.sid.len() - 1] as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for Uid { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_proc.info.uid; let fmt_content = format!("{}", uid); let raw_content = uid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/uid_fs.rs000064400000000000000000000020301046102023000151260ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct UidFs { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UidFs { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("FUID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for UidFs { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let uid = status.fuid; (format!("{uid}"), uid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/uid_login.rs000064400000000000000000000022301046102023000156300ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; const UID_NOT_SET: u32 = 0xffffffff; pub struct UidLogin { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UidLogin { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("LoginUID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for UidLogin { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Ok(uid) = proc.curr_proc.loginuid() { if uid == UID_NOT_SET { (String::new(), uid) } else { (format!("{uid}"), uid) } } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/uid_real.rs000064400000000000000000000035001046102023000154440ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct UidReal { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UidReal { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("RUID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UidReal { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let uid = status.ruid; (format!("{uid}"), uid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for UidReal { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_task.pbsd.pbi_ruid; let fmt_content = format!("{}", uid); let raw_content = uid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for UidReal { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_proc.info.ruid; let fmt_content = format!("{}", uid); let raw_content = uid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/uid_saved.rs000064400000000000000000000035071046102023000156320ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct UidSaved { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UidSaved { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("SUID")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UidSaved { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if let Some(ref status) = proc.curr_status { let uid = status.suid; (format!("{uid}"), uid) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for UidSaved { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_task.pbsd.pbi_svuid; let fmt_content = format!("{}", uid); let raw_content = uid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for UidSaved { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_proc.info.svuid; let fmt_content = format!("{}", uid); let raw_content = uid; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/usage_cpu.rs000064400000000000000000000074031046102023000156410ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct UsageCpu { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UsageCpu { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("CPU")); let unit = String::from("[%]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UsageCpu { fn add(&mut self, proc: &ProcessInfo) { let curr_stat = proc.curr_proc.stat(); let prev_stat = &proc.prev_stat; let curr_time = curr_stat.utime + curr_stat.stime; let prev_time = prev_stat.utime + prev_stat.stime; let usage_ms = (curr_time - prev_time) * 1000 / procfs::ticks_per_second(); let interval_ms = proc.interval.as_secs() * 1000 + u64::from(proc.interval.subsec_millis()); let usage = usage_ms as f64 * 100.0 / interval_ms as f64; let fmt_content = format!("{usage:.1}"); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for UsageCpu { fn add(&mut self, proc: &ProcessInfo) { let curr_time = proc.curr_task.ptinfo.pti_total_user + proc.curr_task.ptinfo.pti_total_system; let prev_time = proc.prev_task.ptinfo.pti_total_user + proc.prev_task.ptinfo.pti_total_system; let usage_ms = (curr_time - prev_time) / 1000000u64; let interval_ms = proc.interval.as_secs() * 1000 + u64::from(proc.interval.subsec_millis()); let usage = usage_ms as f64 * 100.0 / interval_ms as f64; let fmt_content = format!("{:.1}", usage); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "windows")] impl Column for UsageCpu { fn add(&mut self, proc: &ProcessInfo) { let curr_time = proc.cpu_info.curr_sys + proc.cpu_info.curr_user; let prev_time = proc.cpu_info.prev_sys + proc.cpu_info.prev_user; let usage_ms = (curr_time - prev_time) / 10000u64; let interval_ms = proc.interval.as_secs() * 1000 + u64::from(proc.interval.subsec_millis()); let usage = usage_ms as f64 * 100.0 / interval_ms as f64; let fmt_content = format!("{:.1}", usage); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for UsageCpu { fn add(&mut self, proc: &ProcessInfo) { let curr_time = (proc.curr_proc.info.rusage.utime.to_us() + proc.curr_proc.info.rusage.stime.to_us()) as u64; let prev_time = (proc.prev_proc.info.rusage.utime.to_us() + proc.prev_proc.info.rusage.stime.to_us()) as u64; let usage_ms = (curr_time - prev_time) / 1_000u64; let interval_ms = proc.interval.as_secs() * 1000 + u64::from(proc.interval.subsec_millis()); let usage = usage_ms as f64 * 100.0 / interval_ms as f64; let fmt_content = format!("{:.1}", usage); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/usage_mem.rs000064400000000000000000000101411046102023000156210ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; #[cfg(any(target_os = "linux", target_os = "android"))] use procfs::{Current, Meminfo, WithCurrentSystemInfo}; use std::cmp; use std::collections::HashMap; #[cfg(target_os = "windows")] use std::mem::{size_of, zeroed}; #[cfg(target_os = "windows")] use windows_sys::Win32::System::ProcessStatus::{GetPerformanceInfo, PERFORMANCE_INFORMATION}; pub struct UsageMem { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, mem_total: u64, } impl UsageMem { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("MEM")); let unit = String::from("[%]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, mem_total: get_mem_total(), } } } #[cfg(any(target_os = "linux", target_os = "android"))] fn get_mem_total() -> u64 { let meminfo = Meminfo::current(); if let Ok(meminfo) = meminfo { meminfo.mem_total } else { 0 } } #[cfg(target_os = "macos")] fn get_mem_total() -> u64 { let mut mem_total: u64 = 0; let mut mib = [0, 0]; unsafe { crate::util::get_sys_value( libc::CTL_HW as u32, libc::HW_MEMSIZE as u32, std::mem::size_of::(), &mut mem_total as *mut u64 as *mut libc::c_void, &mut mib, ); } mem_total } #[cfg(target_os = "windows")] fn get_mem_total() -> u64 { let mut info: PERFORMANCE_INFORMATION = unsafe { zeroed() }; let ret = unsafe { GetPerformanceInfo(&mut info, size_of::() as u32) }; if ret != 0 { info.PhysicalTotal as u64 * info.PageSize as u64 } else { 0 } } #[cfg(target_os = "freebsd")] fn get_mem_total() -> u64 { let mut mem_total: u64 = 0; let name = std::ffi::CString::new("hw.availpages").unwrap(); let mut size = std::mem::size_of::(); let ptr: *mut u64 = &mut mem_total; unsafe { libc::sysctlbyname( name.as_ptr(), ptr as *mut libc::c_void, &mut size, std::ptr::null(), 0, ); } mem_total } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UsageMem { fn add(&mut self, proc: &ProcessInfo) { let usage = proc.curr_proc.stat().rss_bytes().get() as f64 * 100.0 / self.mem_total as f64; let fmt_content = format!("{usage:.1}"); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "macos")] impl Column for UsageMem { fn add(&mut self, proc: &ProcessInfo) { let usage = proc.curr_task.ptinfo.pti_resident_size as f64 * 100.0 / self.mem_total as f64; let fmt_content = format!("{:.1}", usage); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "windows")] impl Column for UsageMem { fn add(&mut self, proc: &ProcessInfo) { let usage = proc.memory_info.working_set_size as f64 * 100.0 / self.mem_total as f64; let fmt_content = format!("{:.1}", usage); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } #[cfg(target_os = "freebsd")] impl Column for UsageMem { fn add(&mut self, proc: &ProcessInfo) { let usage = proc.curr_proc.info.rssize as f64 * 100.0 / self.mem_total as f64; let fmt_content = format!("{:.1}", usage); let raw_content = (usage * 1000.0) as u32; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u32); } procs-0.14.9/src/columns/user.rs000064400000000000000000000060771046102023000146520ustar 00000000000000use crate::process::ProcessInfo; #[cfg(target_os = "windows")] use crate::util::format_sid; #[cfg(not(target_os = "windows"))] use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; #[cfg(not(target_os = "windows"))] use uzers::Users; pub struct User { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, #[allow(dead_code)] abbr_sid: bool, } impl User { pub fn new(header: Option, abbr_sid: bool) -> Self { let header = header.unwrap_or_else(|| String::from("User")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, abbr_sid, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for User { fn add(&mut self, proc: &ProcessInfo) { let user = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(proc.curr_proc.owner())); let fmt_content = if let Some(user) = user { format!("{}", user.name().to_string_lossy()) } else { format!("{}", proc.curr_proc.owner()) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for User { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_task.pbsd.pbi_uid; let fmt_content = if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{}", uid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "windows")] impl Column for User { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(name) = &proc.user.name { name.clone() } else { format_sid(&proc.user.sid, self.abbr_sid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for User { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_proc.info.uid; let fmt_content = if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{}", uid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/user_fs.rs000064400000000000000000000024611046102023000153330ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Users; pub struct UserFs { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UserFs { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("File System User")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for UserFs { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let uid = status.fuid; if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{uid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/user_login.rs000064400000000000000000000026001046102023000160260ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Users; const UID_NOT_SET: u32 = 0xffffffff; pub struct UserLogin { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UserLogin { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Login User")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for UserLogin { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(uid) = proc.curr_proc.loginuid() { if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else if uid == UID_NOT_SET { String::new() } else { format!("{uid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/user_real.rs000064400000000000000000000050221046102023000156420ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Users; pub struct UserReal { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UserReal { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Real User")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UserReal { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let uid = status.ruid; if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{uid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for UserReal { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_task.pbsd.pbi_ruid; let fmt_content = if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{}", uid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for UserReal { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_proc.info.ruid; let fmt_content = if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{}", uid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/user_saved.rs000064400000000000000000000050321046102023000160220ustar 00000000000000use crate::process::ProcessInfo; use crate::util::USERS_CACHE; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use uzers::Users; pub struct UserSaved { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl UserSaved { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Saved User")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for UserSaved { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Some(ref status) = proc.curr_status { let uid = status.suid; if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{uid}") } } else { String::new() }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "macos")] impl Column for UserSaved { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_task.pbsd.pbi_svuid; let fmt_content = if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{}", uid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for UserSaved { fn add(&mut self, proc: &ProcessInfo) { let uid = proc.curr_proc.info.svuid; let fmt_content = if let Some(user) = USERS_CACHE.with(|x| x.borrow_mut().get_user_by_uid(uid)) { format!("{}", user.name().to_string_lossy()) } else { format!("{}", uid) }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/vm_data.rs000064400000000000000000000032031046102023000152730ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmData { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmData { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmData")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmData { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmdata { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for VmData { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_proc.info.dsize as u64).saturating_mul(4096); let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_exe.rs000064400000000000000000000031751046102023000151530ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmExe { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmExe { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmExe")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmExe { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmexe { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for VmExe { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_proc.info.tsize as u64).saturating_mul(4096); let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_hwm.rs000064400000000000000000000037571046102023000151730ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmHwm { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmHwm { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmHwm")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmHwm { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmhwm { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for VmHwm { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.peak_working_set_size; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for VmHwm { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_proc.info.rusage.maxrss as u64).saturating_mul(4096); let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_lib.rs000064400000000000000000000023121046102023000151300ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmLib { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmLib { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmLib")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for VmLib { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmlib { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_lock.rs000064400000000000000000000023161046102023000153160ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmLock { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmLock { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmLock")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for VmLock { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmlck { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_peak.rs000064400000000000000000000031611046102023000153050ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmPeak { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmPeak { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmPeak")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmPeak { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmpeak { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for VmPeak { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.peak_page_file_usage; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_pin.rs000064400000000000000000000031611046102023000151530ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmPin { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmPin { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmPin")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmPin { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmpin { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for VmPin { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.quota_non_paged_pool_usage; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_pte.rs000064400000000000000000000023121046102023000151520ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmPte { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmPte { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmPte")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } impl Column for VmPte { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmpte { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_rss.rs000064400000000000000000000042031046102023000151720ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmRss { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmRss { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmRSS")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmRss { fn add(&mut self, proc: &ProcessInfo) { use procfs::WithCurrentSystemInfo; let raw_content = proc.curr_proc.stat().rss_bytes().get(); let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for VmRss { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.ptinfo.pti_resident_size; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for VmRss { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.working_set_size; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for VmRss { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_proc.info.rssize as u64).saturating_mul(4096); let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_size.rs000064400000000000000000000040661046102023000153440ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmSize { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmSize { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmSize")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmSize { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.stat().vsize; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for VmSize { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_task.ptinfo.pti_virtual_size; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for VmSize { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.private_usage; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for VmSize { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.info.size as u64; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_stack.rs000064400000000000000000000032071046102023000154730ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmStack { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmStack { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmStack")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmStack { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmstk { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for VmStack { fn add(&mut self, proc: &ProcessInfo) { let raw_content = (proc.curr_proc.info.ssize as u64).saturating_mul(4096); let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/vm_swap.rs000064400000000000000000000031631046102023000153410ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct VmSwap { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl VmSwap { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("VmSwap")); let unit = String::from("[bytes]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for VmSwap { fn add(&mut self, proc: &ProcessInfo) { let (raw_content, fmt_content) = if let Some(ref curr_status) = proc.curr_status { if let Some(val) = curr_status.vmswap { let val = val.saturating_mul(1024); (val, bytify(val)) } else { (0, String::new()) } } else { (0, String::new()) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for VmSwap { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.memory_info.quota_paged_pool_usage; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns/wchan.rs000064400000000000000000000031121046102023000147570ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct Wchan { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl Wchan { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Wchan")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for Wchan { fn add(&mut self, proc: &ProcessInfo) { let raw_content = proc.curr_proc.wchan().unwrap_or_default(); let fmt_content = if raw_content == "0" { String::from("-") } else { raw_content.clone() }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } #[cfg(target_os = "freebsd")] impl Column for Wchan { fn add(&mut self, proc: &ProcessInfo) { let raw_content = if let Ok(wmesg) = crate::util::ptr_to_cstr(&proc.curr_proc.info.wmesg) { wmesg.to_string_lossy().into_owned() } else { String::from("") }; let fmt_content = raw_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/work_dir.rs000064400000000000000000000025221046102023000155030ustar 00000000000000use crate::process::ProcessInfo; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; use std::path::PathBuf; pub struct WorkDir { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, procfs: Option, } impl WorkDir { pub fn new(header: Option, procfs: Option) -> Self { let header = header.unwrap_or_else(|| String::from("WorkDir")); let unit = String::new(); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, procfs, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for WorkDir { fn add(&mut self, proc: &ProcessInfo) { let fmt_content = if let Ok(proc) = crate::util::process_new(proc.pid, &self.procfs) { if let Ok(path) = proc.cwd() { path.to_string_lossy().to_string() } else { String::from("") } } else { String::from("") }; let raw_content = fmt_content.clone(); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(String); } procs-0.14.9/src/columns/write_bytes.rs000064400000000000000000000064221046102023000162260ustar 00000000000000use crate::process::ProcessInfo; use crate::util::bytify; use crate::{column_default, Column}; use std::cmp; use std::collections::HashMap; pub struct WriteBytes { header: String, unit: String, fmt_contents: HashMap, raw_contents: HashMap, width: usize, } impl WriteBytes { pub fn new(header: Option) -> Self { let header = header.unwrap_or_else(|| String::from("Write")); let unit = String::from("[B/s]"); Self { fmt_contents: HashMap::new(), raw_contents: HashMap::new(), width: 0, header, unit, } } } #[cfg(any(target_os = "linux", target_os = "android"))] impl Column for WriteBytes { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if proc.curr_io.is_some() && proc.prev_io.is_some() { let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.curr_io.as_ref().unwrap().write_bytes - proc.prev_io.as_ref().unwrap().write_bytes) * 1000 / interval_ms; (bytify(io), io) } else { (String::new(), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "macos")] impl Column for WriteBytes { fn add(&mut self, proc: &ProcessInfo) { let (fmt_content, raw_content) = if proc.curr_res.is_some() && proc.prev_res.is_some() { let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.curr_res.as_ref().unwrap().ri_diskio_byteswritten - proc.prev_res.as_ref().unwrap().ri_diskio_byteswritten) * 1000 / interval_ms; (bytify(io), io) } else { (String::from(""), 0) }; self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "windows")] impl Column for WriteBytes { fn add(&mut self, proc: &ProcessInfo) { let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.disk_info.curr_write - proc.disk_info.prev_write) * 1000 / interval_ms; let raw_content = io; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } #[cfg(target_os = "freebsd")] impl Column for WriteBytes { fn add(&mut self, proc: &ProcessInfo) { // io block size: 128KB let block_size = 128 * 1024; let interval_ms = proc.interval.as_secs() + u64::from(proc.interval.subsec_millis()); let io = (proc.curr_proc.info.rusage.oublock as u64 - proc.prev_proc.info.rusage.oublock as u64) * block_size * 1000 / interval_ms; let raw_content = io; let fmt_content = bytify(raw_content); self.fmt_contents.insert(proc.pid, fmt_content); self.raw_contents.insert(proc.pid, raw_content); } column_default!(u64); } procs-0.14.9/src/columns.rs000064400000000000000000000004401046102023000136600ustar 00000000000000#[cfg(any(target_os = "linux", target_os = "android"))] include!("./columns/os_linux.rs"); #[cfg(target_os = "macos")] include!("./columns/os_macos.rs"); #[cfg(target_os = "windows")] include!("./columns/os_windows.rs"); #[cfg(target_os = "freebsd")] include!("./columns/os_freebsd.rs"); procs-0.14.9/src/config.rs000064400000000000000000000454611046102023000134610ustar 00000000000000use crate::column::Column; use crate::columns::ConfigColumnKind; use serde_derive::{Deserialize, Serialize}; use std::str::FromStr; // --------------------------------------------------------------------------------------------------------------------- // Functions for serde default // --------------------------------------------------------------------------------------------------------------------- fn default_true() -> bool { true } fn default_false() -> bool { false } fn default_column_style_by_unit() -> ConfigColumnStyle { ConfigColumnStyle::ByUnit } fn default_column_align_left() -> ConfigColumnAlign { ConfigColumnAlign::Left } fn default_color_mode_auto() -> ConfigColorMode { ConfigColorMode::Auto } fn default_pager_mode_auto() -> ConfigPagerMode { ConfigPagerMode::Auto } fn default_search_kind_exact() -> ConfigSearchKind { ConfigSearchKind::Exact } fn default_search_kind_partial() -> ConfigSearchKind { ConfigSearchKind::Partial } fn default_search_logic_and() -> ConfigSearchLogic { ConfigSearchLogic::And } fn default_search_case_smart() -> ConfigSearchCase { ConfigSearchCase::Smart } fn default_sort_order_ascending() -> ConfigSortOrder { ConfigSortOrder::Ascending } fn default_separator() -> String { String::from("│") } fn default_ascending() -> String { String::from("▲") } fn default_descending() -> String { String::from("▼") } fn default_tree_symbols() -> [String; 5] { [ String::from("│"), String::from("─"), String::from("┬"), String::from("├"), String::from("└"), ] } fn default_color_by_theme() -> ConfigColorByTheme { ConfigColorByTheme { dark: ConfigColor::BrightWhite, light: ConfigColor::Black, } } fn default_theme_auto() -> ConfigTheme { ConfigTheme::Auto } // --------------------------------------------------------------------------------------------------------------------- // ColumnInfo // --------------------------------------------------------------------------------------------------------------------- pub struct ColumnInfo { pub column: Box, pub kind: ConfigColumnKind, pub style: ConfigColumnStyle, pub nonnumeric_search: bool, pub numeric_search: bool, pub align: ConfigColumnAlign, pub max_width: Option, pub min_width: Option, pub visible: bool, } // --------------------------------------------------------------------------------------------------------------------- // Config // --------------------------------------------------------------------------------------------------------------------- #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Config { pub columns: Vec, #[serde(default)] pub style: ConfigStyle, #[serde(default)] pub search: ConfigSearch, #[serde(default)] pub display: ConfigDisplay, #[serde(default)] pub sort: ConfigSort, #[serde(default)] pub docker: ConfigDocker, #[serde(default)] pub pager: ConfigPager, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigTheme { Auto, Dark, Light, } #[derive(Clone, Debug, PartialEq, Eq)] pub enum ConfigColor { BrightBlack, BrightRed, BrightGreen, BrightYellow, BrightBlue, BrightMagenta, BrightCyan, BrightWhite, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, Color256(u8), } fn serialize_color(c: &ConfigColor) -> String { match c { ConfigColor::BrightBlack => "BrightBlack".to_string(), ConfigColor::BrightRed => "BrightRed".to_string(), ConfigColor::BrightGreen => "BrightGreen".to_string(), ConfigColor::BrightYellow => "BrightYellow".to_string(), ConfigColor::BrightBlue => "BrightBlue".to_string(), ConfigColor::BrightMagenta => "BrightMagenta".to_string(), ConfigColor::BrightCyan => "BrightCyan".to_string(), ConfigColor::BrightWhite => "BrightWhite".to_string(), ConfigColor::Black => "Black".to_string(), ConfigColor::Red => "Red".to_string(), ConfigColor::Green => "Green".to_string(), ConfigColor::Yellow => "Yellow".to_string(), ConfigColor::Blue => "Blue".to_string(), ConfigColor::Magenta => "Magenta".to_string(), ConfigColor::Cyan => "Cyan".to_string(), ConfigColor::White => "White".to_string(), ConfigColor::Color256(x) => format!("{x}"), } } fn deserialize_color(s: &str) -> Option { match s { "BrightBlack" => Some(ConfigColor::BrightBlack), "BrightRed" => Some(ConfigColor::BrightRed), "BrightGreen" => Some(ConfigColor::BrightGreen), "BrightYellow" => Some(ConfigColor::BrightYellow), "BrightBlue" => Some(ConfigColor::BrightBlue), "BrightMagenta" => Some(ConfigColor::BrightMagenta), "BrightCyan" => Some(ConfigColor::BrightCyan), "BrightWhite" => Some(ConfigColor::BrightWhite), "Black" => Some(ConfigColor::Black), "Red" => Some(ConfigColor::Red), "Green" => Some(ConfigColor::Green), "Yellow" => Some(ConfigColor::Yellow), "Blue" => Some(ConfigColor::Blue), "Magenta" => Some(ConfigColor::Magenta), "Cyan" => Some(ConfigColor::Cyan), "White" => Some(ConfigColor::White), s if u8::from_str(s).is_ok() => Some(ConfigColor::Color256(u8::from_str(s).unwrap())), _ => None, } } fn serialize_color_by_theme(c: &ConfigColorByTheme) -> String { let dark = &c.dark; let light = &c.light; if dark == light { serialize_color(dark) } else { let dark = serialize_color(dark); let light = serialize_color(light); format!("{dark}|{light}") } } fn deserialize_color_by_theme(s: &str) -> Option { if let Some(i) = s.find('|') { let (dark, light) = s.split_at(i); let light = &light[1..]; let dark = deserialize_color(dark)?; let light = deserialize_color(light)?; Some(ConfigColorByTheme { dark, light }) } else { let c = deserialize_color(s)?; Some(ConfigColorByTheme { dark: c.clone(), light: c, }) } } #[derive(Clone, Debug)] pub struct ConfigColorByTheme { pub dark: ConfigColor, pub light: ConfigColor, } impl serde::Serialize for ConfigColorByTheme { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let s = serialize_color_by_theme(self); serializer.serialize_str(&s) } } impl<'de> serde::Deserialize<'de> for ConfigColorByTheme { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let s = String::deserialize(deserializer)?; deserialize_color_by_theme(&s).ok_or_else(|| serde::de::Error::custom("")) } } #[derive(Clone, Debug)] pub enum ConfigColumnStyle { Fixed(ConfigColorByTheme), ByPercentage, ByState, ByUnit, } impl serde::Serialize for ConfigColumnStyle { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let s = match self { ConfigColumnStyle::ByPercentage => "ByPercentage".to_string(), ConfigColumnStyle::ByState => "ByState".to_string(), ConfigColumnStyle::ByUnit => "ByUnit".to_string(), ConfigColumnStyle::Fixed(c) => serialize_color_by_theme(c), }; serializer.serialize_str(&s) } } impl<'de> serde::Deserialize<'de> for ConfigColumnStyle { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let s = String::deserialize(deserializer)?; match s.as_str() { "ByPercentage" => Ok(ConfigColumnStyle::ByPercentage), "ByState" => Ok(ConfigColumnStyle::ByState), "ByUnit" => Ok(ConfigColumnStyle::ByUnit), s => { let c = deserialize_color_by_theme(s).ok_or_else(|| serde::de::Error::custom(""))?; Ok(ConfigColumnStyle::Fixed(c)) } } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigColumnAlign { Left, Right, Center, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigColumn { pub kind: ConfigColumnKind, #[serde(default = "default_column_style_by_unit")] pub style: ConfigColumnStyle, #[serde(default = "default_false")] pub numeric_search: bool, #[serde(default = "default_false")] pub nonnumeric_search: bool, #[serde(default = "default_column_align_left")] pub align: ConfigColumnAlign, pub max_width: Option, pub min_width: Option, pub header: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyle { #[serde(default = "default_color_by_theme")] pub header: ConfigColorByTheme, #[serde(default = "default_color_by_theme")] pub unit: ConfigColorByTheme, #[serde(default = "default_color_by_theme")] pub tree: ConfigColorByTheme, #[serde(default)] pub by_percentage: ConfigStyleByPercentage, #[serde(default)] pub by_state: ConfigStyleByState, #[serde(default)] pub by_unit: ConfigStyleByUnit, } impl Default for ConfigStyle { fn default() -> Self { ConfigStyle { header: default_color_by_theme(), unit: default_color_by_theme(), tree: default_color_by_theme(), by_percentage: Default::default(), by_state: Default::default(), by_unit: Default::default(), } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyleByPercentage { pub color_000: ConfigColorByTheme, pub color_025: ConfigColorByTheme, pub color_050: ConfigColorByTheme, pub color_075: ConfigColorByTheme, pub color_100: ConfigColorByTheme, } impl Default for ConfigStyleByPercentage { fn default() -> Self { ConfigStyleByPercentage { color_000: ConfigColorByTheme { dark: ConfigColor::BrightBlue, light: ConfigColor::Blue, }, color_025: ConfigColorByTheme { dark: ConfigColor::BrightGreen, light: ConfigColor::Green, }, color_050: ConfigColorByTheme { dark: ConfigColor::BrightYellow, light: ConfigColor::Yellow, }, color_075: ConfigColorByTheme { dark: ConfigColor::BrightRed, light: ConfigColor::Red, }, color_100: ConfigColorByTheme { dark: ConfigColor::BrightRed, light: ConfigColor::Red, }, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyleByUnit { pub color_k: ConfigColorByTheme, pub color_m: ConfigColorByTheme, pub color_g: ConfigColorByTheme, pub color_t: ConfigColorByTheme, pub color_p: ConfigColorByTheme, pub color_x: ConfigColorByTheme, } impl Default for ConfigStyleByUnit { fn default() -> Self { ConfigStyleByUnit { color_k: ConfigColorByTheme { dark: ConfigColor::BrightBlue, light: ConfigColor::Blue, }, color_m: ConfigColorByTheme { dark: ConfigColor::BrightGreen, light: ConfigColor::Green, }, color_g: ConfigColorByTheme { dark: ConfigColor::BrightYellow, light: ConfigColor::Yellow, }, color_t: ConfigColorByTheme { dark: ConfigColor::BrightRed, light: ConfigColor::Red, }, color_p: ConfigColorByTheme { dark: ConfigColor::BrightRed, light: ConfigColor::Red, }, color_x: ConfigColorByTheme { dark: ConfigColor::BrightBlue, light: ConfigColor::Blue, }, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigStyleByState { pub color_d: ConfigColorByTheme, pub color_r: ConfigColorByTheme, pub color_s: ConfigColorByTheme, pub color_t: ConfigColorByTheme, pub color_z: ConfigColorByTheme, pub color_x: ConfigColorByTheme, pub color_k: ConfigColorByTheme, pub color_w: ConfigColorByTheme, pub color_p: ConfigColorByTheme, } impl Default for ConfigStyleByState { fn default() -> Self { ConfigStyleByState { color_d: ConfigColorByTheme { dark: ConfigColor::BrightRed, light: ConfigColor::Red, }, color_r: ConfigColorByTheme { dark: ConfigColor::BrightGreen, light: ConfigColor::Green, }, color_s: ConfigColorByTheme { dark: ConfigColor::BrightBlue, light: ConfigColor::Blue, }, color_t: ConfigColorByTheme { dark: ConfigColor::BrightCyan, light: ConfigColor::Cyan, }, color_z: ConfigColorByTheme { dark: ConfigColor::BrightMagenta, light: ConfigColor::Magenta, }, color_x: ConfigColorByTheme { dark: ConfigColor::BrightMagenta, light: ConfigColor::Magenta, }, color_k: ConfigColorByTheme { dark: ConfigColor::BrightYellow, light: ConfigColor::Yellow, }, color_w: ConfigColorByTheme { dark: ConfigColor::BrightYellow, light: ConfigColor::Yellow, }, color_p: ConfigColorByTheme { dark: ConfigColor::BrightYellow, light: ConfigColor::Yellow, }, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigSearch { #[serde(default = "default_search_kind_exact")] pub numeric_search: ConfigSearchKind, #[serde(default = "default_search_kind_partial")] pub nonnumeric_search: ConfigSearchKind, #[serde(default = "default_search_logic_and")] pub logic: ConfigSearchLogic, #[serde(default = "default_search_case_smart")] pub case: ConfigSearchCase, } impl Default for ConfigSearch { fn default() -> Self { ConfigSearch { numeric_search: ConfigSearchKind::Exact, nonnumeric_search: ConfigSearchKind::Partial, logic: ConfigSearchLogic::And, case: ConfigSearchCase::Smart, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigSearchKind { Exact, Partial, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigSearchLogic { And, Or, Nand, Nor, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigSearchCase { Smart, Insensitive, Sensitive, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigDisplay { #[serde(default = "default_false")] pub show_self: bool, #[serde(default = "default_false")] pub show_self_parents: bool, #[serde(default = "default_false")] pub show_thread: bool, #[serde(default = "default_true")] pub show_thread_in_tree: bool, #[serde(default = "default_true")] pub show_parent_in_tree: bool, #[serde(default = "default_true")] pub show_children_in_tree: bool, #[serde(default = "default_true")] pub show_header: bool, #[serde(default = "default_false")] pub show_footer: bool, #[serde(default = "default_true")] pub cut_to_terminal: bool, #[serde(default = "default_false")] pub cut_to_pager: bool, #[serde(default = "default_false")] pub cut_to_pipe: bool, #[serde(default = "default_color_mode_auto")] pub color_mode: ConfigColorMode, #[serde(default = "default_separator")] pub separator: String, #[serde(default = "default_ascending")] pub ascending: String, #[serde(default = "default_descending")] pub descending: String, #[serde(default = "default_tree_symbols")] pub tree_symbols: [String; 5], #[serde(default = "default_true")] pub abbr_sid: bool, #[serde(default = "default_theme_auto")] pub theme: ConfigTheme, #[serde(default = "default_true")] pub show_kthreads: bool, } impl Default for ConfigDisplay { fn default() -> Self { ConfigDisplay { show_self: false, show_self_parents: false, show_thread: false, show_thread_in_tree: true, show_parent_in_tree: true, show_children_in_tree: true, show_header: true, show_footer: false, cut_to_terminal: true, cut_to_pager: false, cut_to_pipe: false, color_mode: ConfigColorMode::Auto, separator: String::from("│"), ascending: String::from("▲"), descending: String::from("▼"), tree_symbols: [ String::from("│"), String::from("─"), String::from("┬"), String::from("├"), String::from("└"), ], abbr_sid: true, theme: ConfigTheme::Auto, show_kthreads: true, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigColorMode { Auto, Always, Disable, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigSort { #[serde(default)] pub column: usize, #[serde(default = "default_sort_order_ascending")] pub order: ConfigSortOrder, } impl Default for ConfigSort { fn default() -> Self { ConfigSort { column: 0, order: ConfigSortOrder::Ascending, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigSortOrder { Ascending, Descending, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigDocker { pub path: String, } impl Default for ConfigDocker { fn default() -> Self { ConfigDocker { path: std::env::var("DOCKER_HOST") .unwrap_or(String::from("unix:///var/run/docker.sock")), } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigPager { #[serde(default = "default_pager_mode_auto")] pub mode: ConfigPagerMode, #[serde(default = "default_false")] pub detect_width: bool, #[serde(default = "default_false")] pub use_builtin: bool, pub command: Option, } impl Default for ConfigPager { fn default() -> Self { ConfigPager { mode: ConfigPagerMode::Auto, detect_width: false, use_builtin: false, command: None, } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigPagerMode { Auto, Always, Disable, } procs-0.14.9/src/main.rs000064400000000000000000000365571046102023000131460ustar 00000000000000mod column; mod columns; mod config; mod process; mod style; mod term_info; mod util; mod view; mod watcher; use crate::column::Column; use crate::columns::*; use crate::config::*; use crate::util::{adjust, get_theme, lap, ArgColorMode, ArgPagerMode, ArgThemeMode}; use crate::view::View; use crate::watcher::Watcher; use anyhow::{anyhow, Context, Error}; use clap::builder::styling::{AnsiColor, Effects, Styles}; use clap::{CommandFactory, Parser, ValueEnum}; use clap_complete::Shell; use console::Term; use std::cmp; use std::collections::HashMap; use std::fs; use std::io::{stdout, Read}; use std::path::PathBuf; use std::time::Instant; use unicode_width::UnicodeWidthStr; // --------------------------------------------------------------------------------------------------------------------- // Opt // --------------------------------------------------------------------------------------------------------------------- #[derive(Clone, Debug, ValueEnum)] pub enum BuiltinConfig { Default, Large, } #[derive(Debug, Parser)] #[clap(long_version(option_env!("LONG_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"))))] #[clap( styles(Styles::styled() .header(AnsiColor::Yellow.on_default() | Effects::BOLD) .usage(AnsiColor::Yellow.on_default() | Effects::BOLD) .literal(AnsiColor::Green.on_default() | Effects::BOLD) .placeholder(AnsiColor::Cyan.on_default()) ) )] /// A modern replacement for ps /// /// please see https://github.com/dalance/procs#configuration to configure columns pub struct Opt { /// Keywords for search #[clap(action, name = "KEYWORD")] pub keyword: Vec, /// AND logic for multi-keyword #[clap( short = 'a', long = "and", conflicts_with_all(&["or", "nand", "nor"]) )] pub and: bool, /// OR logic for multi-keyword #[clap( short = 'o', long = "or", conflicts_with_all(&["and", "nand", "nor"]) )] pub or: bool, /// NAND logic for multi-keyword #[clap( short = 'd', long = "nand", conflicts_with_all(&["and", "or", "nor"]) )] pub nand: bool, /// NOR logic for multi-keyword #[clap( short = 'r', long = "nor", conflicts_with_all(&["and", "or", "nand"]) )] pub nor: bool, /// Show list of kind #[clap(short = 'l', long = "list")] pub list: bool, /// Show thread #[clap(long = "thread")] pub thread: bool, /// Tree view #[clap(short = 't', long = "tree")] pub tree: bool, /// Watch mode with default interval (1s) #[clap(short = 'w', long = "watch")] pub watch: bool, /// Watch mode with custom interval #[clap(short = 'W', long = "watch-interval", value_name = "second")] pub watch_interval: Option, #[clap(skip)] pub watch_mode: bool, /// Insert column to slot #[clap(value_name = "kind", short = 'i', long = "insert", number_of_values(1))] pub insert: Vec, /// Specified column only #[clap(value_name = "kind", long = "only")] pub only: Option, /// Sort column by ascending #[clap( value_name = "kind", long = "sorta", conflicts_with_all(&["sortd", "tree"]) )] pub sorta: Option, /// Sort column by descending #[clap( value_name = "kind", long = "sortd", conflicts_with_all(&["sorta", "tree"]) )] pub sortd: Option, /// Color mode #[clap(short = 'c', long = "color")] pub color: Option, /// Theme mode #[clap(long = "theme")] pub theme: Option, /// Pager mode #[clap(short = 'p', long = "pager")] pub pager: Option, /// Interval to calculate throughput #[clap(long = "interval", default_value = "100", value_name = "millisec")] pub interval: u64, /// Use built-in configuration #[clap(long = "use-config", value_name = "name")] pub use_config: Option, /// Load configuration from file #[clap(long = "load-config", value_name = "path")] pub load_config: Option, /// Generate configuration sample file #[clap(long = "gen-config")] pub gen_config: bool, /// Generate shell completion file #[clap(long = "gen-completion", value_name = "shell")] pub gen_completion: Option, /// Generate shell completion file and write to stdout #[clap(long = "gen-completion-out", value_name = "shell")] pub gen_completion_out: Option, /// Suppress header #[clap(long = "no-header")] pub no_header: bool, /// Path to procfs #[clap(long = "procfs")] pub procfs: Option, /// Show debug message #[clap(long = "debug", hide = true)] pub debug: bool, } // --------------------------------------------------------------------------------------------------------------------- // Functions // --------------------------------------------------------------------------------------------------------------------- fn get_config(opt: &Opt) -> Result { let dot_cfg_path = directories::BaseDirs::new() .map(|base| base.home_dir().join(".procs.toml")) .filter(|path| path.exists()); let app_cfg_path = directories::ProjectDirs::from("com.github", "dalance", "procs") .map(|proj| proj.preference_dir().join("config.toml")) .filter(|path| path.exists()); let xdg_cfg_path = directories::BaseDirs::new() .map(|base| { base.home_dir() .join(".config") .join("procs") .join("config.toml") }) .filter(|path| path.exists()); let etc_path = PathBuf::from("/etc/procs/procs.toml"); let etc_cfg_path = etc_path.exists().then_some(etc_path); let cfg_path = opt .load_config .clone() .or(dot_cfg_path) .or(app_cfg_path) .or(xdg_cfg_path) .or(etc_cfg_path); let config: Config = if let Some(path) = cfg_path { let mut f = fs::File::open(&path).context(format!("failed to open file ({path:?})"))?; let mut s = String::new(); f.read_to_string(&mut s) .context(format!("failed to read file ({path:?})"))?; let c = toml::from_str(&s); check_old_config(&s, c).context(format!("failed to parse toml ({path:?})"))? } else { toml::from_str(CONFIG_DEFAULT).unwrap() }; match opt.use_config { Some(BuiltinConfig::Default) => Ok(toml::from_str(CONFIG_DEFAULT).unwrap()), Some(BuiltinConfig::Large) => Ok(toml::from_str(CONFIG_LARGE).unwrap()), None => Ok(config), } } fn check_old_config(s: &str, config: Result) -> Result { match config { Ok(x) => Ok(x), Err(x) => { if s.contains("Color256") { let err: Error = x.into(); let err = err.context("\"Color256\" keyword for 8bit color is obsolete. Please see https://github.com/dalance/procs#color-list"); Err(err) } else { Err(x.into()) } } } } // --------------------------------------------------------------------------------------------------------------------- // Main // --------------------------------------------------------------------------------------------------------------------- fn main() { let err = Term::stderr(); if let Err(x) = run() { let mut cause = x.chain(); let _ = err.write_line(&format!( "{} {}", console::style("error:").red().bold(), cause.next().unwrap() )); for x in cause { let _ = err.write_line(&format!(" {} {}", console::style("caused by:").red(), x)); } std::process::exit(1); } } fn run() -> Result<(), Error> { let mut opt: Opt = Parser::parse(); opt.watch_mode = opt.watch || opt.watch_interval.is_some(); if opt.gen_config { run_gen_config() } else if opt.list { run_list(); Ok(()) } else if let Some(shell) = opt.gen_completion { //Opt::clap().gen_completions("procs", shell, "./"); clap_complete::generate_to(shell, &mut Opt::command(), "procs", "./")?; let path = match shell { Shell::Bash => "./procs.bash", Shell::Elvish => "./procs.elv", Shell::Fish => "./procs.fish", Shell::PowerShell => "./_procs.ps1", Shell::Zsh => "./_procs", x => return Err(anyhow!("unknown shell type: {}", x)), }; println!("completion file is generated: {path}"); Ok(()) } else if let Some(shell) = opt.gen_completion_out { //Opt::clap().gen_completions_to("procs", shell, &mut stdout()); clap_complete::generate(shell, &mut Opt::command(), "procs", &mut stdout()); Ok(()) } else { let config = get_config(&opt)?; if opt.watch_mode { let interval = match opt.watch_interval { Some(n) => (n * 1000.0).round() as u64, None => 1000, }; run_watch(&mut opt, &config, interval) } else { run_default(&mut opt, &config) } } } fn run_gen_config() -> Result<(), Error> { let config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); let toml = toml::to_string(&config)?; println!("{toml}"); Ok(()) } fn run_list() { let mut width = 0; let mut list = Vec::new(); let mut desc = HashMap::new(); for (_, (v, d)) in KIND_LIST.iter() { list.push(v); desc.insert(v, d); width = cmp::max(width, UnicodeWidthStr::width(*v)); } println!("Column kind list:"); for l in list { println!( " {}: {}", adjust(l, width, &ConfigColumnAlign::Left), desc[l] ); } } fn run_watch(opt: &mut Opt, config: &Config, interval: u64) -> Result<(), Error> { Watcher::start(opt, config, interval) } fn run_default(opt: &mut Opt, config: &Config) -> Result<(), Error> { let mut time = Instant::now(); let theme = get_theme(opt, config); let mut view = View::new(opt, config, false)?; if opt.debug { lap(&mut time, "Info: View::new"); } view.filter(opt, config, 1); if opt.debug { lap(&mut time, "Info: view.filter"); } view.adjust(config, &HashMap::new()); if opt.debug { lap(&mut time, "Info: view.adjust"); } view.display(opt, config, &theme)?; if opt.debug { lap(&mut time, "Info: view.display"); } Ok(()) } #[cfg(test)] mod tests { use super::*; #[test] fn test_run() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let args = vec!["procs"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_search() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "root"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); let args = vec!["procs", "1"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); let args = vec!["procs", "--or", "root", "1"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); let args = vec!["procs", "--and", "root", "1"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); let args = vec!["procs", "--nor", "root", "1"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); let args = vec!["procs", "--nand", "root", "1"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); config.search.nonnumeric_search = ConfigSearchKind::Exact; config.search.numeric_search = ConfigSearchKind::Partial; let args = vec!["procs", "root", "1"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_gen_config() { let ret = run_gen_config(); assert!(ret.is_ok()); } #[test] fn test_run_without_truncate() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.display.cut_to_terminal = false; config.display.theme = ConfigTheme::Dark; let args = vec!["procs"]; let mut opt = Opt::parse_from(args.iter()); config.pager.mode = ConfigPagerMode::Disable; let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_insert() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--insert", "ppid"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_sort() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--sorta", "cpu"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); let args = vec!["procs", "--sortd", "cpu"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_tree() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--tree"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_all() { let mut config: Config = toml::from_str(CONFIG_ALL).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let _tcp = std::net::TcpListener::bind("127.0.0.1:10000"); let _udp = std::net::UdpSocket::bind("127.0.0.1:10000"); let args = vec!["procs"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } #[test] fn test_run_use_config() { let mut config: Config = toml::from_str(CONFIG_DEFAULT).unwrap(); config.pager.mode = ConfigPagerMode::Disable; config.display.theme = ConfigTheme::Dark; let args = vec!["procs", "--use-config", "large"]; let mut opt = Opt::parse_from(args.iter()); let ret = run_default(&mut opt, &config); assert!(ret.is_ok()); } } procs-0.14.9/src/process/freebsd.rs000064400000000000000000000026721046102023000153010ustar 00000000000000use bsd_kvm::{Access, KernProc, Kvm, Process}; use std::collections::HashMap; use std::path::PathBuf; use std::thread; use std::time::{Duration, Instant}; pub struct ProcessInfo { pub pid: i32, pub ppid: i32, pub curr_proc: Process, pub prev_proc: Process, pub interval: Duration, } pub fn collect_proc( interval: Duration, _with_thread: bool, _show_kthreads: bool, _procfs_path: &Option, ) -> Vec { let mut base_procs = HashMap::new(); let mut ret = Vec::new(); let kvm = Kvm::open(None, Some("/dev/null"), Access::ReadOnly); if let Ok(mut kvm) = kvm { for proc in kvm.get_process(KernProc::Proc, 0) { let time = Instant::now(); base_procs.insert(proc.info.pid, (proc.clone(), time)); } thread::sleep(interval); for proc in kvm.get_process(KernProc::Proc, 0) { let pid = proc.info.pid; if let Some((prev_proc, prev_time)) = base_procs.remove(&pid) { let curr_time = Instant::now(); let curr_proc = proc.clone(); let interval = curr_time - prev_time; let proc = ProcessInfo { pid: proc.info.pid, ppid: proc.info.ppid, curr_proc, prev_proc, interval, }; ret.push(proc); } } } ret } procs-0.14.9/src/process/linux.rs000064400000000000000000000132021046102023000150150ustar 00000000000000use procfs::process::{FDInfo, Io, Process, Stat, Status, TasksIter}; use procfs::ProcError; use procfs::ProcessCGroup; use std::collections::HashMap; use std::path::PathBuf; use std::thread; use std::time::{Duration, Instant}; pub enum ProcessTask { Process { stat: Stat, owner: u32, proc: Process, }, Task { stat: Stat, owner: u32, }, } impl ProcessTask { pub fn stat(&self) -> &Stat { match self { ProcessTask::Process { stat: x, .. } => x, ProcessTask::Task { stat: x, .. } => x, } } pub fn cmdline(&self) -> Result, ProcError> { match self { ProcessTask::Process { proc: x, .. } => x.cmdline(), _ => Err(ProcError::Other("not supported".to_string())), } } pub fn cgroups(&self) -> Result, ProcError> { match self { ProcessTask::Process { proc: x, .. } => x.cgroups().map(|x| x.0), _ => Err(ProcError::Other("not supported".to_string())), } } pub fn fd(&self) -> Result, ProcError> { match self { ProcessTask::Process { proc: x, .. } => x.fd()?.collect(), _ => Err(ProcError::Other("not supported".to_string())), } } pub fn loginuid(&self) -> Result { match self { ProcessTask::Process { proc: x, .. } => x.loginuid(), _ => Err(ProcError::Other("not supported".to_string())), } } pub fn owner(&self) -> u32 { match self { ProcessTask::Process { owner: x, .. } => *x, ProcessTask::Task { owner: x, .. } => *x, } } pub fn wchan(&self) -> Result { match self { ProcessTask::Process { proc: x, .. } => x.wchan(), _ => Err(ProcError::Other("not supported".to_string())), } } } pub struct ProcessInfo { pub pid: i32, pub ppid: i32, pub curr_proc: ProcessTask, pub prev_stat: Stat, pub curr_io: Option, pub prev_io: Option, pub curr_status: Option, pub interval: Duration, } pub fn collect_proc( interval: Duration, with_thread: bool, show_kthreads: bool, procfs_path: &Option, ) -> Vec { let mut base_procs = Vec::new(); let mut base_tasks = HashMap::new(); let mut ret = Vec::new(); let all_proc = if let Some(ref x) = procfs_path { procfs::process::all_processes_with_root(x) } else { procfs::process::all_processes() }; if let Ok(all_proc) = all_proc { for proc in all_proc.flatten() { if let Ok(stat) = proc.stat() { let io = proc.io().ok(); let time = Instant::now(); if with_thread { if let Ok(iter) = proc.tasks() { collect_task(iter, &mut base_tasks); } } base_procs.push((proc.pid(), stat, io, time)); } } } thread::sleep(interval); for (pid, prev_stat, prev_io, prev_time) in base_procs { let curr_proc = if let Ok(proc) = crate::util::process_new(pid, procfs_path) { proc } else { continue; }; let curr_stat = if let Ok(stat) = curr_proc.stat() { stat } else { continue; }; let curr_owner = if let Ok(owner) = curr_proc.uid() { owner } else { continue; }; let curr_io = curr_proc.io().ok(); let curr_status = curr_proc.status().ok(); let curr_time = Instant::now(); let interval = curr_time - prev_time; let ppid = curr_stat.ppid; if !show_kthreads && (ppid == 2 || pid == 2) { continue; } let mut curr_tasks = HashMap::new(); if with_thread { if let Ok(iter) = curr_proc.tasks() { collect_task(iter, &mut curr_tasks); } } let curr_proc = ProcessTask::Process { stat: curr_stat, owner: curr_owner, proc: curr_proc, }; let proc = ProcessInfo { pid, ppid, curr_proc, prev_stat, curr_io, prev_io, curr_status, interval, }; ret.push(proc); for (tid, (pid, curr_stat, curr_status, curr_io)) in curr_tasks { if let Some((_, prev_stat, _, prev_io)) = base_tasks.remove(&tid) { let proc = ProcessInfo { pid: tid, ppid: pid, curr_proc: ProcessTask::Task { stat: curr_stat, owner: curr_owner, }, prev_stat, curr_io, prev_io, curr_status, interval, }; ret.push(proc); } } } ret } #[allow(clippy::type_complexity)] fn collect_task(iter: TasksIter, map: &mut HashMap, Option)>) { for task in iter { let task = if let Ok(x) = task { x } else { continue; }; if task.tid != task.pid { let stat = if let Ok(x) = task.stat() { x } else { continue; }; let status = task.status().ok(); let io = task.io().ok(); map.insert(task.tid, (task.pid, stat, status, io)); } } } procs-0.14.9/src/process/macos.rs000064400000000000000000000234401046102023000147650ustar 00000000000000use libc::{c_int, c_void, size_t}; use libproc::libproc::bsd_info::BSDInfo; use libproc::libproc::file_info::{pidfdinfo, ListFDs, ProcFDType}; use libproc::libproc::net_info::{InSockInfo, SocketFDInfo, SocketInfoKind, TcpSockInfo}; use libproc::libproc::pid_rusage::{pidrusage, RUsageInfoV2}; use libproc::libproc::proc_pid::{listpidinfo, pidinfo, ListThreads}; use libproc::libproc::task_info::{TaskAllInfo, TaskInfo}; use libproc::libproc::thread_info::ThreadInfo; use libproc::processes::{pids_by_type, ProcFilter}; use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::thread; use std::time::{Duration, Instant}; pub struct ProcessInfo { pub pid: i32, pub ppid: i32, pub curr_task: TaskAllInfo, pub prev_task: TaskAllInfo, pub curr_path: Option, pub curr_threads: Vec, pub curr_udps: Vec, pub curr_tcps: Vec, pub curr_res: Option, pub prev_res: Option, pub interval: Duration, } pub fn collect_proc( interval: Duration, _with_thread: bool, _show_kthreads: bool, _procfs_path: &Option, ) -> Vec { let mut base_procs = Vec::new(); let mut ret = Vec::new(); let arg_max = get_arg_max(); if let Ok(procs) = pids_by_type(ProcFilter::All) { for p in procs { if let Ok(task) = pidinfo::(p as i32, 0) { let res = pidrusage::(p as i32).ok(); let time = Instant::now(); base_procs.push((p as i32, task, res, time)); } } } thread::sleep(interval); for (pid, prev_task, prev_res, prev_time) in base_procs { let curr_task = if let Ok(task) = pidinfo::(pid, 0) { task } else { clone_task_all_info(&prev_task) }; let curr_path = get_path_info(pid, arg_max); let threadids = listpidinfo::(pid, curr_task.ptinfo.pti_threadnum as usize); let mut curr_threads = Vec::new(); if let Ok(threadids) = threadids { for t in threadids { if let Ok(thread) = pidinfo::(pid, t) { curr_threads.push(thread); } } } let mut curr_tcps = Vec::new(); let mut curr_udps = Vec::new(); let fds = listpidinfo::(pid, curr_task.pbsd.pbi_nfiles as usize); if let Ok(fds) = fds { for fd in fds { if let ProcFDType::Socket = fd.proc_fdtype.into() { if let Ok(socket) = pidfdinfo::(pid, fd.proc_fd) { match socket.psi.soi_kind.into() { SocketInfoKind::In => { if socket.psi.soi_protocol == libc::IPPROTO_UDP { let info = unsafe { socket.psi.soi_proto.pri_in }; curr_udps.push(info); } } SocketInfoKind::Tcp => { let info = unsafe { socket.psi.soi_proto.pri_tcp }; curr_tcps.push(info); } _ => (), } } } } } let curr_res = pidrusage::(pid).ok(); let curr_time = Instant::now(); let interval = curr_time - prev_time; let ppid = curr_task.pbsd.pbi_ppid as i32; let proc = ProcessInfo { pid, ppid, curr_task, prev_task, curr_path, curr_threads, curr_udps, curr_tcps, curr_res, prev_res, interval, }; ret.push(proc); } ret } fn get_arg_max() -> size_t { let mut mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_ARGMAX]; let mut arg_max = 0i32; let mut size = ::std::mem::size_of::(); unsafe { while libc::sysctl( mib.as_mut_ptr(), 2, (&mut arg_max) as *mut i32 as *mut c_void, &mut size, ::std::ptr::null_mut(), 0, ) == -1 {} } arg_max as size_t } pub struct PathInfo { #[allow(dead_code)] pub name: String, #[allow(dead_code)] pub exe: PathBuf, #[allow(dead_code)] pub root: PathBuf, pub cmd: Vec, #[allow(dead_code)] pub env: Vec, } unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String { let len = cp as usize - start as usize; let part = Vec::from_raw_parts(start, len, len); let tmp = String::from_utf8_unchecked(part.clone()); ::std::mem::forget(part); tmp } fn get_path_info(pid: i32, mut size: size_t) -> Option { let mut proc_args = Vec::with_capacity(size as usize); let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr(); let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_PROCARGS2, pid as c_int]; unsafe { let ret = libc::sysctl( mib.as_mut_ptr(), 3, ptr as *mut c_void, &mut size, ::std::ptr::null_mut(), 0, ); if ret != -1 { let mut n_args: c_int = 0; libc::memcpy( (&mut n_args) as *mut c_int as *mut c_void, ptr as *const c_void, ::std::mem::size_of::(), ); let mut cp = ptr.add(::std::mem::size_of::()); let mut start = cp; if cp < ptr.add(size) { while cp < ptr.add(size) && *cp != 0 { cp = cp.offset(1); } let exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf(); let name = exe .file_name() .unwrap_or_else(|| OsStr::new("")) .to_str() .unwrap_or("") .to_owned(); let mut need_root = true; let mut root = Default::default(); if exe.is_absolute() { if let Some(parent) = exe.parent() { root = parent.to_path_buf(); need_root = false; } } while cp < ptr.add(size) && *cp == 0 { cp = cp.offset(1); } start = cp; let mut c = 0; let mut cmd = Vec::new(); while c < n_args && cp < ptr.add(size) { if *cp == 0 { c += 1; cmd.push(get_unchecked_str(cp, start)); start = cp.offset(1); } cp = cp.offset(1); } start = cp; let mut env = Vec::new(); while cp < ptr.add(size) { if *cp == 0 { if cp == start { break; } env.push(get_unchecked_str(cp, start)); start = cp.offset(1); } cp = cp.offset(1); } if need_root { for env in env.iter() { if env.starts_with("PATH=") { root = Path::new(&env[6..]).to_path_buf(); break; } } } Some(PathInfo { exe, name, root, cmd, env, }) } else { None } } else { None } } } fn clone_task_all_info(src: &TaskAllInfo) -> TaskAllInfo { let pbsd = BSDInfo { pbi_flags: src.pbsd.pbi_flags, pbi_status: src.pbsd.pbi_status, pbi_xstatus: src.pbsd.pbi_xstatus, pbi_pid: src.pbsd.pbi_pid, pbi_ppid: src.pbsd.pbi_ppid, pbi_uid: src.pbsd.pbi_uid, pbi_gid: src.pbsd.pbi_gid, pbi_ruid: src.pbsd.pbi_ruid, pbi_rgid: src.pbsd.pbi_rgid, pbi_svuid: src.pbsd.pbi_svuid, pbi_svgid: src.pbsd.pbi_svgid, rfu_1: src.pbsd.rfu_1, pbi_comm: src.pbsd.pbi_comm, pbi_name: src.pbsd.pbi_name, pbi_nfiles: src.pbsd.pbi_nfiles, pbi_pgid: src.pbsd.pbi_pgid, pbi_pjobc: src.pbsd.pbi_pjobc, e_tdev: src.pbsd.e_tdev, e_tpgid: src.pbsd.e_tpgid, pbi_nice: src.pbsd.pbi_nice, pbi_start_tvsec: src.pbsd.pbi_start_tvsec, pbi_start_tvusec: src.pbsd.pbi_start_tvusec, }; let ptinfo = TaskInfo { pti_virtual_size: src.ptinfo.pti_virtual_size, pti_resident_size: src.ptinfo.pti_resident_size, pti_total_user: src.ptinfo.pti_total_user, pti_total_system: src.ptinfo.pti_total_system, pti_threads_user: src.ptinfo.pti_threads_user, pti_threads_system: src.ptinfo.pti_threads_system, pti_policy: src.ptinfo.pti_policy, pti_faults: src.ptinfo.pti_faults, pti_pageins: src.ptinfo.pti_pageins, pti_cow_faults: src.ptinfo.pti_cow_faults, pti_messages_sent: src.ptinfo.pti_messages_sent, pti_messages_received: src.ptinfo.pti_messages_received, pti_syscalls_mach: src.ptinfo.pti_syscalls_mach, pti_syscalls_unix: src.ptinfo.pti_syscalls_unix, pti_csw: src.ptinfo.pti_csw, pti_threadnum: src.ptinfo.pti_threadnum, pti_numrunning: src.ptinfo.pti_numrunning, pti_priority: src.ptinfo.pti_priority, }; TaskAllInfo { pbsd, ptinfo } } procs-0.14.9/src/process/windows.rs000064400000000000000000000431001046102023000153500ustar 00000000000000use chrono::offset::TimeZone; use chrono::{Local, NaiveDate}; use std::cell::RefCell; use std::collections::HashMap; use std::ffi::c_void; use std::mem::{size_of, zeroed, MaybeUninit}; use std::path::PathBuf; use std::ptr; use std::thread; use std::time::{Duration, Instant}; use windows_sys::Win32::Foundation::{CloseHandle, FALSE, FILETIME, HANDLE, HMODULE, MAX_PATH}; use windows_sys::Win32::Security::{ AdjustTokenPrivileges, GetTokenInformation, LookupAccountSidW, LookupPrivilegeValueW, TokenGroups, TokenUser, PSID, SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED, SID, TOKEN_ADJUST_PRIVILEGES, TOKEN_GROUPS, TOKEN_PRIVILEGES, TOKEN_QUERY, TOKEN_USER, }; use windows_sys::Win32::System::Diagnostics::ToolHelp::{ CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS, }; use windows_sys::Win32::System::ProcessStatus::{ EnumProcessModulesEx, GetModuleBaseNameW, GetProcessMemoryInfo, K32EnumProcesses, LIST_MODULES_ALL, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, }; use windows_sys::Win32::System::Threading::{ GetCurrentProcess, GetPriorityClass, GetProcessIoCounters, GetProcessTimes, OpenProcess, OpenProcessToken, IO_COUNTERS, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ, }; pub struct ProcessInfo { pub pid: i32, pub command: String, pub ppid: i32, pub start_time: chrono::DateTime, pub cpu_info: CpuInfo, pub memory_info: MemoryInfo, pub disk_info: DiskInfo, pub user: SidName, pub groups: Vec, pub priority: u32, pub thread: i32, pub interval: Duration, } pub struct MemoryInfo { pub page_fault_count: u64, pub peak_working_set_size: u64, pub working_set_size: u64, #[allow(dead_code)] pub quota_peak_paged_pool_usage: u64, pub quota_paged_pool_usage: u64, #[allow(dead_code)] pub quota_peak_non_paged_pool_usage: u64, pub quota_non_paged_pool_usage: u64, #[allow(dead_code)] pub page_file_usage: u64, pub peak_page_file_usage: u64, pub private_usage: u64, } pub struct DiskInfo { pub prev_read: u64, pub prev_write: u64, pub curr_read: u64, pub curr_write: u64, } pub struct CpuInfo { pub prev_sys: u64, pub prev_user: u64, pub curr_sys: u64, pub curr_user: u64, } pub fn collect_proc( interval: Duration, _with_thread: bool, _show_kthreads: bool, _procfs_path: &Option, ) -> Vec { let mut base_procs = Vec::new(); let mut ret = Vec::new(); let _ = set_privilege(); for pid in get_pids() { let handle = get_handle(pid); if let Some(handle) = handle { let times = get_times(handle); let io = get_io(handle); let time = Instant::now(); if let (Some((_, _, sys, user)), Some((read, write))) = (times, io) { base_procs.push((pid, sys, user, read, write, time)); } } } thread::sleep(interval); let (mut ppids, mut threads) = get_ppid_threads(); for (pid, prev_sys, prev_user, prev_read, prev_write, prev_time) in base_procs { let ppid = ppids.remove(&pid); let thread = threads.remove(&pid); let handle = get_handle(pid); if let Some(handle) = handle { let command = get_command(handle); let memory_info = get_memory_info(handle); let times = get_times(handle); let io = get_io(handle); let start_time = if let Some((start, _, _, _)) = times { let time = chrono::Duration::seconds(start as i64 / 10_000_000); let base = NaiveDate::from_ymd_opt(1601, 1, 1) .and_then(|ndate| ndate.and_hms_opt(0, 0, 0)) .unwrap(); let time = base + time; let local = Local.from_utc_datetime(&time); Some(local) } else { None }; let cpu_info = if let Some((_, _, curr_sys, curr_user)) = times { Some(CpuInfo { prev_sys, prev_user, curr_sys, curr_user, }) } else { None }; let disk_info = if let Some((curr_read, curr_write)) = io { Some(DiskInfo { prev_read, prev_write, curr_read, curr_write, }) } else { None }; let user = get_user(handle); let groups = get_groups(handle); let priority = get_priority(handle); let curr_time = Instant::now(); let interval = curr_time - prev_time; let mut all_ok = true; all_ok &= command.is_some(); all_ok &= start_time.is_some(); all_ok &= cpu_info.is_some(); all_ok &= memory_info.is_some(); all_ok &= disk_info.is_some(); all_ok &= user.is_some(); all_ok &= groups.is_some(); all_ok &= thread.is_some(); if all_ok { let command = command.unwrap(); let ppid = ppid.unwrap_or(0); let start_time = start_time.unwrap(); let cpu_info = cpu_info.unwrap(); let memory_info = memory_info.unwrap(); let disk_info = disk_info.unwrap(); let user = user.unwrap(); let groups = groups.unwrap(); let thread = thread.unwrap(); let proc = ProcessInfo { pid, command, ppid, start_time, cpu_info, memory_info, disk_info, user, groups, priority, thread, interval, }; ret.push(proc); } unsafe { CloseHandle(handle); } } } ret } fn set_privilege() -> bool { let handle = unsafe { GetCurrentProcess() }; let mut token: HANDLE = unsafe { zeroed() }; let ret = unsafe { OpenProcessToken(handle, TOKEN_ADJUST_PRIVILEGES, &mut token) }; if ret == 0 { return false; } let mut tps: TOKEN_PRIVILEGES = unsafe { zeroed() }; let se_debug_name: Vec = format!("{}\0", unsafe { *SE_DEBUG_NAME }) .encode_utf16() .collect(); tps.PrivilegeCount = 1; let ret = unsafe { LookupPrivilegeValueW( ptr::null(), se_debug_name.as_ptr(), &mut tps.Privileges[0].Luid, ) }; if ret == 0 { return false; } tps.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; let ret = unsafe { AdjustTokenPrivileges( token, FALSE, &tps as *const _, 0, ptr::null::() as *mut TOKEN_PRIVILEGES, ptr::null::() as *mut u32, ) }; if ret == 0 { return false; } true } fn get_pids() -> Vec { let dword_size = size_of::(); let mut pids = Vec::with_capacity(10192); let mut cb_needed = 0; unsafe { pids.set_len(10192) }; let result = unsafe { K32EnumProcesses( pids.as_mut_ptr(), (dword_size * pids.len()) as u32, &mut cb_needed, ) }; if result == 0 { return Vec::new(); } let pids_len = cb_needed / dword_size as u32; unsafe { pids.set_len(pids_len as usize) }; pids.iter().map(|x| *x as i32).collect() } fn get_ppid_threads() -> (HashMap, HashMap) { let mut ppids = HashMap::new(); let mut threads = HashMap::new(); let snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; let mut entry: PROCESSENTRY32 = unsafe { zeroed() }; entry.dwSize = size_of::() as u32; let mut not_the_end = unsafe { Process32First(snapshot, &mut entry) }; while not_the_end != 0 { ppids.insert(entry.th32ProcessID as i32, entry.th32ParentProcessID as i32); threads.insert(entry.th32ProcessID as i32, entry.cntThreads as i32); not_the_end = unsafe { Process32Next(snapshot, &mut entry) }; } unsafe { CloseHandle(snapshot) }; (ppids, threads) } fn get_handle(pid: i32) -> Option { if pid == 0 { return None; } let handle = unsafe { OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid as u32, ) }; if handle == std::ptr::null_mut() { None } else { Some(handle) } } fn get_times(handle: HANDLE) -> Option<(u64, u64, u64, u64)> { let mut start: FILETIME = unsafe { zeroed() }; let mut exit: FILETIME = unsafe { zeroed() }; let mut sys: FILETIME = unsafe { zeroed() }; let mut user: FILETIME = unsafe { zeroed() }; let ret = unsafe { GetProcessTimes( handle, &mut start as *mut FILETIME, &mut exit as *mut FILETIME, &mut sys as *mut FILETIME, &mut user as *mut FILETIME, ) }; let start = u64::from(start.dwHighDateTime) << 32 | u64::from(start.dwLowDateTime); let exit = u64::from(exit.dwHighDateTime) << 32 | u64::from(exit.dwLowDateTime); let sys = u64::from(sys.dwHighDateTime) << 32 | u64::from(sys.dwLowDateTime); let user = u64::from(user.dwHighDateTime) << 32 | u64::from(user.dwLowDateTime); if ret != 0 { Some((start, exit, sys, user)) } else { None } } fn get_memory_info(handle: HANDLE) -> Option { let mut pmc: PROCESS_MEMORY_COUNTERS_EX = unsafe { zeroed() }; let ret = unsafe { GetProcessMemoryInfo( handle, &mut pmc as *mut PROCESS_MEMORY_COUNTERS_EX as *mut c_void as *mut PROCESS_MEMORY_COUNTERS, size_of::() as u32, ) }; if ret != 0 { let info = MemoryInfo { page_fault_count: u64::from(pmc.PageFaultCount), peak_working_set_size: pmc.PeakWorkingSetSize as u64, working_set_size: pmc.WorkingSetSize as u64, quota_peak_paged_pool_usage: pmc.QuotaPeakPagedPoolUsage as u64, quota_paged_pool_usage: pmc.QuotaPagedPoolUsage as u64, quota_peak_non_paged_pool_usage: pmc.QuotaPeakNonPagedPoolUsage as u64, quota_non_paged_pool_usage: pmc.QuotaNonPagedPoolUsage as u64, page_file_usage: pmc.PagefileUsage as u64, peak_page_file_usage: pmc.PeakPagefileUsage as u64, private_usage: pmc.PrivateUsage as u64, }; Some(info) } else { None } } fn get_command(handle: HANDLE) -> Option { let mut exe_buf = [0u16; MAX_PATH as usize + 1]; let h_mod: HMODULE = std::ptr::null_mut(); let mut cb_needed = 0; let ret = unsafe { EnumProcessModulesEx( handle, h_mod as *mut HMODULE, size_of::() as u32, &mut cb_needed, LIST_MODULES_ALL, ) }; if ret == 0 { return None; } let ret = unsafe { GetModuleBaseNameW(handle, h_mod, exe_buf.as_mut_ptr(), MAX_PATH + 1) }; let mut pos = 0; for x in exe_buf.iter() { if *x == 0 { break; } pos += 1; } if ret != 0 { Some(String::from_utf16_lossy(&exe_buf[..pos])) } else { None } } fn get_io(handle: HANDLE) -> Option<(u64, u64)> { let mut io: IO_COUNTERS = unsafe { zeroed() }; let ret = unsafe { GetProcessIoCounters(handle, &mut io) }; if ret != 0 { Some((io.ReadTransferCount, io.WriteTransferCount)) } else { None } } pub struct SidName { pub sid: Vec, pub name: Option, #[allow(dead_code)] pub domainname: Option, } fn get_user(handle: HANDLE) -> Option { let mut token: HANDLE = unsafe { zeroed() }; let ret = unsafe { OpenProcessToken(handle, TOKEN_QUERY, &mut token) }; if ret == 0 { return None; } let mut cb_needed = 0; let _ = unsafe { GetTokenInformation( token, TokenUser, ptr::null::() as *mut c_void, 0, &mut cb_needed, ) }; let mut buf: Vec> = Vec::with_capacity(cb_needed as usize); unsafe { buf.set_len(cb_needed as usize); } let ret = unsafe { GetTokenInformation( token, TokenUser, buf.as_mut_ptr() as *mut c_void, cb_needed, &mut cb_needed, ) }; if ret == 0 { return None; } #[allow(clippy::cast_ptr_alignment)] let token_user = buf.as_ptr() as *const TOKEN_USER; let psid = unsafe { (*token_user).User.Sid }; let sid = get_sid(psid); let (name, domainname) = if let Some((x, y)) = get_name_cached(psid) { (Some(x), Some(y)) } else { (None, None) }; Some(SidName { sid, name, domainname, }) } fn get_groups(handle: HANDLE) -> Option> { unsafe { let mut token: HANDLE = zeroed(); let ret = OpenProcessToken(handle, TOKEN_QUERY, &mut token); if ret == 0 { return None; } let mut cb_needed = 0; let _ = GetTokenInformation( token, TokenGroups, ptr::null::() as *mut c_void, 0, &mut cb_needed, ); let mut buf: Vec> = Vec::with_capacity(cb_needed as usize); buf.set_len(cb_needed as usize); let ret = GetTokenInformation( token, TokenGroups, buf.as_mut_ptr() as *mut c_void, cb_needed, &mut cb_needed, ); if ret == 0 { return None; } #[allow(clippy::cast_ptr_alignment)] let token_groups = buf.as_ptr() as *const TOKEN_GROUPS; let mut ret = Vec::new(); let sa = (*token_groups).Groups.as_ptr(); for i in 0..(*token_groups).GroupCount { let psid = (*sa.offset(i as isize)).Sid; let sid = get_sid(psid); let (name, domainname) = if let Some((x, y)) = get_name_cached(psid) { (Some(x), Some(y)) } else { (None, None) }; let sid_name = SidName { sid, name, domainname, }; ret.push(sid_name); } Some(ret) } } fn get_sid(psid: PSID) -> Vec { let mut ret = Vec::new(); let psid = psid as *const SID; unsafe { let mut ia = 0; ia |= u64::from((*psid).IdentifierAuthority.Value[0]) << 40; ia |= u64::from((*psid).IdentifierAuthority.Value[1]) << 32; ia |= u64::from((*psid).IdentifierAuthority.Value[2]) << 24; ia |= u64::from((*psid).IdentifierAuthority.Value[3]) << 16; ia |= u64::from((*psid).IdentifierAuthority.Value[4]) << 8; ia |= u64::from((*psid).IdentifierAuthority.Value[5]); ret.push(u64::from((*psid).Revision)); ret.push(ia); let cnt = (*psid).SubAuthorityCount; let sa = (*psid).SubAuthority.as_ptr(); for i in 0..cnt { ret.push(u64::from(*sa.offset(i as isize))); } ret } } thread_local!( pub static NAME_CACHE: RefCell>> = RefCell::new(HashMap::new()); ); fn get_name_cached(psid: PSID) -> Option<(String, String)> { NAME_CACHE.with(|c| { let mut c = c.borrow_mut(); if let Some(x) = c.get(&psid) { x.clone() } else { let x = get_name(psid); c.insert(psid, x.clone()); x } }) } fn get_name(psid: PSID) -> Option<(String, String)> { let mut cc_name = 0; let mut cc_domainname = 0; let mut pe_use = 0; unsafe { let _ = LookupAccountSidW( ptr::null::() as *mut u16, psid, ptr::null::() as *mut u16, &mut cc_name, ptr::null::() as *mut u16, &mut cc_domainname, &mut pe_use, ); if cc_name == 0 || cc_domainname == 0 { return None; } let mut name: Vec = Vec::with_capacity(cc_name as usize); let mut domainname: Vec = Vec::with_capacity(cc_domainname as usize); name.set_len(cc_name as usize); domainname.set_len(cc_domainname as usize); let ret = LookupAccountSidW( ptr::null::() as *mut u16, psid, name.as_mut_ptr(), &mut cc_name, domainname.as_mut_ptr(), &mut cc_domainname, &mut pe_use, ); if ret == 0 { return None; } let name = from_wide_ptr(name.as_ptr()); let domainname = from_wide_ptr(domainname.as_ptr()); Some((name, domainname)) } } fn from_wide_ptr(ptr: *const u16) -> String { use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; assert!(!ptr.is_null()); let len = (0..isize::MAX) .position(|i| unsafe { *ptr.offset(i) == 0 }) .unwrap(); let slice = unsafe { std::slice::from_raw_parts(ptr, len) }; OsString::from_wide(slice).to_string_lossy().into_owned() } fn get_priority(handle: HANDLE) -> u32 { unsafe { GetPriorityClass(handle) } } procs-0.14.9/src/process.rs000064400000000000000000000007051046102023000136620ustar 00000000000000#[cfg(target_os = "freebsd")] pub mod freebsd; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod linux; #[cfg(target_os = "macos")] pub mod macos; #[cfg(target_os = "windows")] pub mod windows; #[cfg(target_os = "freebsd")] pub use self::freebsd::*; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; #[cfg(target_os = "macos")] pub use self::macos::*; #[cfg(target_os = "windows")] pub use self::windows::*; procs-0.14.9/src/style.rs000064400000000000000000000152121046102023000133430ustar 00000000000000use crate::config::{ConfigColor, ConfigColorByTheme, ConfigColumnStyle, ConfigStyle, ConfigTheme}; use console::{Style, StyledObject}; use once_cell::sync::Lazy; static BRIGHT_BLACK: Lazy