#!/usr/bin/env bash # ------------------------------------------------------------------------------ # Copyright (c) 2013-2026 Geoffray Levasseur # Protected by the BSD3 license. Please read bellow for details. # # * Redistribution and use in source and binary forms, # * with or without modification, are permitted provided # * that the following conditions are met: # * # * Redistributions of source code must retain the above # * copyright notice, this list of conditions and the # * following disclaimer. # * # * Redistributions in binary form must reproduce the above # * copyright notice, this list of conditions and the following # * disclaimer in the documentation and/or other materials # * provided with the distribution. # * # * Neither the name of the copyright holder nor the names # * of any other contributors may be used to endorse or # * promote products derived from this software without # * specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR # * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # * OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Show profile version # Usage: ver ver() { local PARSED PARSED=$(getopt -o h --long help -n 'ver' -- "$@") # shellcheck disable=SC2181 # getopt return code is checked immediately after if [[ $? -ne 0 ]]; then disp E "Invalid options, use \"ver --help\" to display usage." return 1 fi eval set -- "$PARSED" while true; do case "$1" in -h|--help) printf "ver: Display the current profile version.\nUsage: ver\n" return 0 ;; --) shift break ;; *) disp E "Invalid options, use \"ver --help\" to display usage." return 1 ;; esac done [[ -z $PROFVERSION ]] && \ disp W "No version defined. Profile is probably badly installed." && \ return 1 disp "Profile version $PROFVERSION." } export -f ver # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Display weather for the given city (or the default one) # Usage: meteo [city1 city2 ...] meteo() { local PARSED PARSED=$(getopt -o h --long help -n 'meteo' -- "$@") # shellcheck disable=SC2181 # getopt return code is checked immediately after if [[ $? -ne 0 ]]; then disp E "Invalid options, use \"meteo --help\" to display usage." return 1 fi eval set -- "$PARSED" while true; do case "$1" in -h|--help) printf "meteo: Fetch weather data.\n" printf "Usage: meteo [city1 city2 ...]\n" printf "If no city is provided, the default city from configuration will be used.\n" return 0 ;; --) shift break ;; *) disp E "Invalid options, use \"meteo --help\" to display usage." return 1 ;; esac done local cities=("$@") local city="" encoded="" [[ $# -eq 0 ]] && cities=("${METEO_DEFAULT_CITY:-}") if [[ ${#cities[@]} -eq 0 || -z "${cities[0]}" ]]; then disp E "No city given and METEO_DEFAULT_CITY is not set. Use 'meteo '." return 1 fi for city in "${cities[@]}"; do encoded=$(urlencode "$city") dwl "https://wttr.in/$encoded" || \ disp E "Failed to fetch weather data for $city." done } export -f meteo # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Display a system information block using only /proc and /sys — no external tools. # Usage: pinfo pinfo() { local _row _row() { printf " %b%-12s%b %b%s%b\n" "$_lbl" "$1" "$_rst" "$_val" "$2" "$_rst" } local PARSED PARSED=$(getopt -o h --long help -n 'pinfo' -- "$@") # shellcheck disable=SC2181 if [[ $? -ne 0 ]]; then disp E "Invalid options, use \"pinfo --help\" to display usage." return 1 fi eval set -- "$PARSED" while true; do case "$1" in -h|--help) printf "pinfo: Display system information from /proc and /sys (no external tools required).\n" printf "Usage: pinfo\n" return 0 ;; --) shift break ;; *) disp E "Invalid options, use \"pinfo --help\" to display usage." return 1 ;; esac done # --- Hostname --- local hostname_str if [[ -r /proc/sys/kernel/hostname ]]; then read -r hostname_str < /proc/sys/kernel/hostname else hostname_str="${HOSTNAME:-unknown}" fi # --- OS release (security: parsed line by line, never sourced) --- local os_name="Unknown" os_version="" if [[ -r /etc/os-release ]]; then local _osr_key _osr_val while IFS='=' read -r _osr_key _osr_val; do _osr_val="${_osr_val//\"/}" case "$_osr_key" in NAME) os_name="$_osr_val" ;; VERSION_ID) os_version="$_osr_val" ;; esac done < /etc/os-release fi # --- Kernel release --- local kernel_str="unknown" [[ -r /proc/sys/kernel/osrelease ]] && read -r kernel_str < /proc/sys/kernel/osrelease # --- Architecture (set by bash at startup from the ELF interpreter) --- local arch_str="${HOSTTYPE:-unknown}" # --- Uptime (seconds from /proc/uptime) --- local uptime_str="unknown" if [[ -r /proc/uptime ]]; then local _upraw read -r _upraw _ < /proc/uptime local _upsec="${_upraw%%.*}" local _days=$(( _upsec / 86400 )) local _hours=$(( (_upsec % 86400) / 3600 )) local _mins=$(( (_upsec % 3600) / 60 )) local _secs=$(( _upsec % 60 )) uptime_str="" (( _days > 0 )) && uptime_str+="${_days}d " (( _hours > 0 || _days > 0 )) && uptime_str+="${_hours}h " uptime_str+="${_mins}m ${_secs}s" fi # --- Load average --- local load_str="unknown" if [[ -r /proc/loadavg ]]; then local _l1 _l5 _l15 read -r _l1 _l5 _l15 _ < /proc/loadavg load_str="${_l1} ${_l5} ${_l15} (1/5/15 min)" fi # --- CPU model and logical/physical core count (pure bash) --- local cpu_model="unknown" cpu_threads=0 local -A _seen_cores=() local _cur_phys="" _cpu_line if [[ -r /proc/cpuinfo ]]; then while IFS= read -r _cpu_line; do case "$_cpu_line" in "model name"*|"Model name"*|"Hardware"*) [[ "$cpu_model" == "unknown" ]] && cpu_model="${_cpu_line#*: }" ;; "processor"*) (( cpu_threads++ )) ;; "physical id"*) _cur_phys="${_cpu_line#*: }" ;; "core id"*) _seen_cores["${_cur_phys}:${_cpu_line#*: }"]=1 ;; esac done < /proc/cpuinfo fi local cpu_cores="${#_seen_cores[@]}" (( 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 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" ;; SwapTotal) swap_total="$_mval" ;; SwapFree) swap_free="$_mval" ;; esac done < /proc/meminfo fi local mem_total_mib=$(( mem_total / 1024 )) local mem_used_mib=$(( (mem_total - mem_available) / 1024 )) local swap_total_mib=$(( swap_total / 1024 )) local swap_used_mib=$(( (swap_total - swap_free) / 1024 )) # --- Process count (glob over numeric /proc entries) --- local proc_count=0 _pdir for _pdir in /proc/[0-9]*/; do [[ -d "$_pdir" ]] && (( proc_count++ )) done # --- Shell and terminal --- local shell_str="${BASH:-bash} ${BASH_VERSION%\(*}" local term_str="${TERM:-unknown}" # --- 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. for _gdir in /sys/class/drm/card[0-9]*/device; do [[ -d "$_gdir" ]] || continue _gname="" # Try uevent: contains PCI_ID and sometimes DRIVER 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" ;; PCI_ID) _uev_pci="$_uev_val" ;; esac done < "$_gdir/uevent" [[ -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 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*Graphics*) gpu_list+=("$_pci_name") ;; esac done < /proc/bus/pci/devices fi # --- Render --- local _lbl="${BIWhite:-}" _val="${ICyan:-}" _rst="${DEFAULTCOL:-}" printf "\n" _row "Hostname" "$hostname_str" _row "OS" "${os_name}${os_version:+ $os_version}" _row "Kernel" "$kernel_str" _row "Arch" "$arch_str" _row "Uptime" "$uptime_str" _row "Load avg" "$load_str" _row "CPU" "$cpu_model" _row "Cores" "${cpu_cores} physical, ${cpu_threads} logical" if (( ${#gpu_list[@]} > 0 )); then local _gi for _gi in "${!gpu_list[@]}"; do local _gpu_lbl="GPU" (( ${#gpu_list[@]} > 1 )) && _gpu_lbl="GPU $(( _gi + 1 ))" _row "$_gpu_lbl" "${gpu_list[$_gi]}" done fi _row "Memory" "${mem_used_mib} MiB used / ${mem_total_mib} MiB total" if (( swap_total > 0 )); then _row "Swap" "${swap_used_mib} MiB used / ${swap_total_mib} MiB total" fi _row "Processes" "$proc_count" _row "Shell" "$shell_str" _row "Terminal" "$term_str" printf "\n" } export -f pinfo # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Display system general information # Usage: showinfo showinfo() { local PARSED PARSED=$(getopt -o h --long help -n 'showinfo' -- "$@") # shellcheck disable=SC2181 # getopt return code is checked immediately after if [[ $? -ne 0 ]]; then disp E "Invalid options, use \"showinfo --help\" to display usage." return 1 fi eval set -- "$PARSED" while true; do case "$1" in -h|--help) printf "showinfo: Display system information (hostname, kernel, uptime and fetch output when available).\n" printf "Usage: showinfo\n" return 0 ;; --) shift break ;; *) disp E "Invalid options, use \"showinfo --help\" to display usage." return 1 ;; esac done local hostname_str local figopt=() hostname_str="$(hostname)" printf "\n" if command -v figlet >/dev/null 2>&1; then [[ -s /usr/share/figlet/ansi_shadow.flf ]] && \ figopt=(-f ansi_shadow) figlet -k "${figopt[@]}" "$hostname_str" else printf "%s\n" "$hostname_str" fi printf "\n" if command -v neofetch >/dev/null 2>&1; then neofetch elif command -v fastfetch >/dev/null 2>&1; then fastfetch else pinfo "$@" fi } export -f showinfo # ------------------------------------------------------------------------------ load_conf info # EOF