From d2397ecea774d112eb54f10803f79199823904b6 Mon Sep 17 00:00:00 2001 From: fatalerrors Date: Tue, 13 Oct 2026 13:32:18 +0200 Subject: [PATCH] info bug fix, fastfetch is now default --- README.md | 6 +-- doc/CHANGELOG.md | 7 ++++ profile.d/info.sh | 104 ++++++++++++++++++++++++++++------------------ 3 files changed, 74 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 1a3fb85..336bd6a 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ A bar-style prompt showing current time, execution time of the last command | `setlocale` | lang | Set console locale to any installed locale | | `set_theme` | prompt | Switch the prompt colour theme for the session (`--list`, `--preview`, `--save`) | | `settrace` | debug | Activate (`--on`), deactivate (`--off`) or query (`--status`) an ERR trap that prints the exit status and a call stack (on stderr) for each failing command; `--force` replaces/removes an ERR trap set by something else; active at startup when `SETTRACE_DEFAULT_ENABLED=1` | -| `showinfo` | info | Display welcome banner and system information (figlet + neofetch/fastfetch) | +| `showinfo` | info | Display welcome banner and system information (figlet + fastfetch/neofetch) | | `ssr` | ssh | SSH into a server as root, forwarding extra ssh options | | `taz` | compress | Compress files and directories into a chosen archive format | | `term_set` | conf | Set `TERM` to the best available terminal capability | @@ -469,8 +469,8 @@ to load profile or use its core functions. | Binary | Typical package name | Distr. | Function(s) | Behaviour when absent | | --- | --- | --- | --- | --- | | `figlet` | `figlet` | all | `showinfo` | ASCII banner skipped | -| `neofetch` | `neofetch` | all | `showinfo` | Falls back to `fastfetch`, then skipped | -| `fastfetch` | `fastfetch` | all | `showinfo` | Falls back if `neofetch` absent; then skipped | +| `neofetch` | `neofetch` | all | `showinfo` | Used only if `fastfetch` is absent; then falls back to the built-in `pinfo` | +| `fastfetch` | `fastfetch` | all | `showinfo` | Preferred over `neofetch`; if both are absent, falls back to the built-in `pinfo` | | `jq` | `jq` | all | `myextip` | Raw JSON shown instead of formatted output | | `hexdump` | `util-linux` / `bsdmainutils` | all | `busy` | Error message, function returns 1 | | `numfmt` | `coreutils` ≥ 8.21 | all | `file_stats --min/--max` | Error message, function returns 1 | diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 3cf34c4..cf659cf 100755 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -83,6 +83,13 @@ Versions follow `MAJOR.MINOR.PATCH-REVISION_STAGE_N` (e.g. `3.99.1-4_rc_1`). - `help`: `help ` no longer runs arbitrary external programs with `--help` (profile functions only); `NO_COLOR` is honoured; `kt`, `pinfo` and `help` itself are listed, and the list is in alphabetical order again. +- `pinfo`: GPUs were listed once per display connector (nine "GPUs" on a + single-GPU laptop); the `/proc/bus/pci` fallback could never match; free + memory is estimated on kernels without `MemAvailable`; `/usr/lib/os-release` + is used as a fallback; `NO_COLOR` is honoured; internal variables and the + helper no longer leak into the shell. `showinfo` no longer needs the + `hostname` binary. +- `showinfo`: `fastfetch` is now preferred over the unmaintained `neofetch`. - `compress.sh`: option flags and loop variables no longer leak into the interactive shell. diff --git a/profile.d/info.sh b/profile.d/info.sh index 9c480d2..1d1519b 100644 --- a/profile.d/info.sh +++ b/profile.d/info.sh @@ -50,9 +50,8 @@ ver() return 1 fi - local -a _pargs=() - readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0') - set -- "${_pargs[@]}" + # Restore the getopt-normalised (shell-quoted) argument list + eval set -- "$PARSED" while true; do case "$1" in -h|--help) @@ -70,7 +69,7 @@ ver() esac done - [[ -z $PROFVERSION ]] && \ + [[ -z ${PROFVERSION:-} ]] && \ disp W "No version defined. Profile is probably badly installed." && \ return 1 disp "Profile version $PROFVERSION." @@ -92,9 +91,8 @@ meteo() disp E "Invalid options, use \"meteo --help\" to display usage." return 1 fi - local -a _pargs=() - readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0') - set -- "${_pargs[@]}" + # Restore the getopt-normalised (shell-quoted) argument list + eval set -- "$PARSED" while true; do case "$1" in -h|--help) @@ -150,9 +148,8 @@ pinfo() disp E "Invalid options, use \"pinfo --help\" to display usage." return 1 fi - local -a _pargs=() - readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0') - set -- "${_pargs[@]}" + # Restore the getopt-normalised (shell-quoted) argument list + eval set -- "$PARSED" while true; do case "$1" in -h|--help) @@ -180,16 +177,24 @@ pinfo() fi # --- OS release (security: parsed line by line, never sourced) --- - local os_name="Unknown" os_version="" + # /usr/lib/os-release is the documented fallback location. Values may be + # wrapped in double or single quotes. + local os_name="Unknown" os_version="" _osr_file="" if [[ -r /etc/os-release ]]; then + _osr_file=/etc/os-release + elif [[ -r /usr/lib/os-release ]]; then + _osr_file=/usr/lib/os-release + fi + if [[ -n $_osr_file ]]; then local _osr_key _osr_val while IFS='=' read -r _osr_key _osr_val; do _osr_val="${_osr_val//\"/}" + _osr_val="${_osr_val//\'/}" case "$_osr_key" in NAME) os_name="$_osr_val" ;; VERSION_ID) os_version="$_osr_val" ;; esac - done < /etc/os-release + done < "$_osr_file" fi # --- Kernel release --- @@ -249,18 +254,25 @@ pinfo() (( cpu_cores == 0 )) && cpu_cores=$cpu_threads # --- Memory (pure bash, /proc/meminfo, values in kB) --- - local mem_total=0 mem_available=0 swap_total=0 swap_free=0 + # MemAvailable only exists since Linux 3.14; on older kernels it is + # estimated as free + buffers + cached. + local mem_total=0 mem_available=-1 mem_free=0 mem_buffers=0 mem_cached=0 + local swap_total=0 swap_free=0 if [[ -r /proc/meminfo ]]; then local _mkey _mval _munit while read -r _mkey _mval _munit; do case "${_mkey%:}" in MemTotal) mem_total="$_mval" ;; MemAvailable) mem_available="$_mval" ;; + MemFree) mem_free="$_mval" ;; + Buffers) mem_buffers="$_mval" ;; + Cached) mem_cached="$_mval" ;; SwapTotal) swap_total="$_mval" ;; SwapFree) swap_free="$_mval" ;; esac done < /proc/meminfo fi + (( mem_available < 0 )) && mem_available=$(( mem_free + mem_buffers + mem_cached )) local mem_total_mib=$(( mem_total / 1024 )) local mem_used_mib=$(( (mem_total - mem_available) / 1024 )) local swap_total_mib=$(( swap_total / 1024 )) @@ -278,16 +290,19 @@ pinfo() # --- GPU (no external tools required; sysfs first, then /proc/bus/pci) --- local -a gpu_list=() - local _gdir _gname _gline - # Preferred: sysfs drm — each card has a device/vendor+device pair readable - # without root. The human-readable name comes from the uevent file. + local _gdir _gname _uev_key _uev_val _uev_driver _uev_pci + # Preferred: sysfs drm — each card has a device/uevent file readable + # without root, giving the PCI id and the kernel driver in use. A label + # file (rarely provided by drivers) wins when present. for _gdir in /sys/class/drm/card[0-9]*/device; do [[ -d "$_gdir" ]] || continue + # Connector entries (card0-eDP-1, card0-HDMI-A-1, ...) also carry a + # "device" link to the same GPU: keep the plain "cardN" entries only. + _gname="${_gdir%/device}" + [[ "${_gname##*/}" =~ ^card[0-9]+$ ]] || continue _gname="" - # Try uevent: contains PCI_ID and sometimes DRIVER + _uev_driver="" _uev_pci="" if [[ -r "$_gdir/uevent" ]]; then - local _uev_driver="" _uev_pci="" - local _uev_line while IFS='=' read -r _uev_key _uev_val; do case "$_uev_key" in DRIVER) _uev_driver="$_uev_val" ;; @@ -297,35 +312,40 @@ pinfo() [[ -n "$_uev_pci" ]] && _gname="PCI ${_uev_pci}" [[ -n "$_uev_driver" ]] && _gname+=" (${_uev_driver})" fi - # Better: label file written by driver (e.g. amdgpu, i915) if [[ -r "$_gdir/label" ]]; then read -r _gname < "$_gdir/label" elif [[ -r "$_gdir/../label" ]]; then read -r _gname < "$_gdir/../label" fi - # Better still: product name from hwmon or power supply description - # Try modalias vendor/device text via /sys/.../subsystem_device not always human - # Last resort: readable model via drm connector name [[ -z "$_gname" ]] && _gname="unknown GPU" gpu_list+=("$_gname") done - # Fallback: scan /proc/bus/pci/devices — field 1 is vendor:device hex, field 14 is name + # Fallback: /proc/bus/pci/devices. It holds no human-readable name: the + # tab-separated fields are the bus address, vendor+device ids (8 hex + # digits), IRQ, the base addresses and sizes, then the kernel driver name + # as the last field when one is bound. Only well-known GPU drivers are + # reported, as vendor ids alone also match every other device of a vendor. if (( ${#gpu_list[@]} == 0 )) && [[ -r /proc/bus/pci/devices ]]; then - while IFS=$'\t' read -r _pci_bus _pci_id _pci_irq _rest _pci_name; do - # Display class is in the high 16 bits of field 2 (vendor:device word) - # /proc/bus/pci/devices col 1 is busdevfn, col 2 is vendorID<<16|deviceID - # The class 0x03xx is "Display controller / VGA compatible" - case "$_pci_name" in - *VGA*|*Display*|*3D*|*GPU*|*Graphics*|*Radeon*|*GeForce*|*Intel*Iris*|*Intel*UHD*|*Intel*HD*) - gpu_list+=("$_pci_name") + local -a _pci=() + local _pci_id _pci_drv + while IFS=$'\t' read -r -a _pci; do + _pci_drv="${_pci[-1]// /}" + case "$_pci_drv" in + i915|xe|amdgpu|radeon|nouveau|nvidia|virtio-pci|vmwgfx|qxl|bochs-drm|cirrus|mgag200|ast) + _pci_id="${_pci[1]}" + gpu_list+=("PCI ${_pci_id:0:4}:${_pci_id:4:4} (${_pci_drv})") ;; esac done < /proc/bus/pci/devices fi # --- Render --- + # Colours are dropped under NO_COLOR, like everywhere else in the profile. local _lbl="${BIWhite:-}" _val="${ICyan:-}" _rst="${DEFAULTCOL:-}" + if [[ -n ${NO_COLOR:-} ]]; then + _lbl="" _val="" _rst="" + fi printf "\n" _row "Hostname" "$hostname_str" @@ -352,6 +372,7 @@ pinfo() _row "Shell" "$shell_str" _row "Terminal" "$term_str" printf "\n" + unset -f _row } export -f pinfo # ------------------------------------------------------------------------------ @@ -370,9 +391,8 @@ showinfo() disp E "Invalid options, use \"showinfo --help\" to display usage." return 1 fi - local -a _pargs=() - readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0') - set -- "${_pargs[@]}" + # Restore the getopt-normalised (shell-quoted) argument list + eval set -- "$PARSED" while true; do case "$1" in @@ -392,9 +412,13 @@ showinfo() esac done - local hostname_str - local figopt=() - hostname_str="$(hostname)" + local hostname_str figopt=() + # /proc first: the hostname binary is missing from minimal installations + if [[ -r /proc/sys/kernel/hostname ]]; then + read -r hostname_str < /proc/sys/kernel/hostname + else + hostname_str="${HOSTNAME:-$(hostname 2>/dev/null)}" + fi printf "\n" if command -v figlet >/dev/null 2>&1; then @@ -406,10 +430,10 @@ showinfo() fi printf "\n" - if command -v neofetch >/dev/null 2>&1; then - neofetch - elif command -v fastfetch >/dev/null 2>&1; then + if command -v fastfetch >/dev/null 2>&1; then fastfetch + elif command -v neofetch >/dev/null 2>&1; then + neofetch else pinfo "$@" fi