diff options
Diffstat (limited to 'lib/panel/hwmon')
-rwxr-xr-x | lib/panel/hwmon | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/lib/panel/hwmon b/lib/panel/hwmon new file mode 100755 index 0000000..5e32d3e --- /dev/null +++ b/lib/panel/hwmon @@ -0,0 +1,290 @@ +#!/bin/sh +# +# hwmon -- Panel applet to monitor Linux hwmon (temp, fan, and power) sensors +# +# Copyright (C) 2018 Patrick "P. J." McDermott +# +# 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. + +set -eu + +cr=0 +debug=0 + +err() +{ + local fmt="${1}" + shift 1 + + printf "Error: ${fmt}\n" "${@}" 1>&2 + return 0 +} + +dbg() +{ + local fmt="${1}" + shift 1 + + case "${debug}" in '1') + printf "DEBUG: ${fmt}\n" "${@}" 1>&2 + esac + + return 0 +} + +lookup_chips() +{ + local hwmon_dir= + local hwmon= + local name= + + for hwmon_dir in /sys/class/hwmon/hwmon*; do + hwmon="${hwmon_dir#/sys/class/hwmon/}" + if [ -f "${hwmon_dir}/name" ]; then + read -r name <"${hwmon_dir}/name" + elif [ -f "${hwmon_dir}/device/name" ]; then + read -r name <"${hwmon_dir}/device/name" + else + return 1 + fi + printf '%s %s\n' "${hwmon}" "${name}" + dbg 'Chip %s = %s' "${name}" "${hwmon}" + done + + return 0 +} + +lookup_chip() +{ + local chip="${1}" + local chips="${2}" + shift 2 + local hwmon= + local name= + + while read -r hwmon name; do + case "${name}" in "${chip}") + printf '%s' "${hwmon}" + return 0 + esac + done <<-EOF + ${chips} + EOF + + return 1 +} + +read_value() +{ + local hwmon="${1}" + local element="${2}" + shift 2 + local hwmon_dir= + local value= + + hwmon_dir="/sys/class/hwmon/${hwmon}" + if [ -f "${hwmon_dir}/${element}_input" ]; then + read -r value <"${hwmon_dir}/${element}_input" + elif [ -f "${hwmon_dir}/device/${element}_input" ]; then + read -r value <"${hwmon_dir}/device/${element}_input" + else + return 1 + fi + + printf '%s' "${value}" + return 0 +} + +format_temp() +{ + local hwmon="${1}" + local element="${2}" + shift 2 + local value= + + value="$(read_value "${hwmon}" "${element}")" || return 1 + printf '%d C' "${value%???}" + + return 0 +} + +format_fan() +{ + local hwmon="${1}" + local element="${2}" + shift 2 + local value= + + value="$(read_value "${hwmon}" "${element}")" || return 1 + printf '%d RPM' "${value}" + + return 0 +} + +format_power() +{ + local hwmon="${1}" + local element="${2}" + shift 2 + local value= + + value="$(read_value "${hwmon}" "${element}")" || return 1 + printf '%d W' "${value%??????}" + + return 0 +} + +print_sensor() +{ + local indent=${1} + local label="${2}" + local len=${3} + local chip="${4}" + local chips="${5}" + local element="${6}" + shift 6 + local hwmon= + local value= + local i= + + if ! hwmon="$(lookup_chip "${chip}" "${chips}")"; then + err 'Unknown chip "%s"' "${chip}" + return 1 + fi + + case "${element}" in + 'temp'*) + value="$(format_temp "${hwmon}" "${element}")" || \ + return 1 + ;; + 'fan'*) + value="$(format_fan "${hwmon}" "${element}")" || \ + return 1 + ;; + 'power'*) + value="$(format_power "${hwmon}" "${element}")" || \ + return 1 + ;; + *) + err 'Unsupported type of element "%s"' "${element}" + return 1 + ;; + esac + + i=0 + while [ ${i} -lt ${indent} ]; do + printf ' ' + i=$((${i} + 1)) + done + case "${label}" in ?*) + printf '%s: ' "${label}" + i=${#label} + while [ ${i} -lt ${len} ]; do + printf ' ' + i=$((${i} + 1)) + done + esac + case "${cr}" in + 1) printf '%s\r' "${value}";; + 0) printf '%s\n' "${value}";; + esac + + return 0 +} + +usage() +{ + printf 'Usage: %s [<options>] %s [%s ...]\n' "${0}" \ + '<label>:[<chip>/<element>]' '<label>:[<chip>/<element>]' + printf '\n' + printf 'Options:\n' + printf ' -i <num> Indent label/value lines with <num> spaces\n' + printf ' -r Print carriage returns instead of line feeds\n' + printf ' -d Enable debugging output\n' +} + +main() +{ + local indent= + local opt= + local chips= + local max_len= + local sensor= + local label= + local len= + local chip= + local element= + + indent=0 + while getopts 'i:rd' opt "${@}"; do + case "${opt}" in + 'i') + case "${OPTARG}" in *[!0-9]* | '') + usage 1>&2 + return 1 + esac + indent=${OPTARG} + ;; + 'r') cr=1;; + 'd') debug=1;; + '?') + usage 1>&2 + return 1 + ;; + esac + done + shift $((${OPTIND} - 1)) + + if [ ${#} -lt 1 ]; then + usage 1>&2 + return 1 + fi + + chips="$(lookup_chips)" || return 1 + + max_len=0 + for sensor in "${@}"; do + label="${sensor%%:*}" + len=${#label} + if [ ${len} -gt ${max_len} ]; then + max_len=${len} + fi + done + + for sensor in "${@}"; do + label="${sensor%%:*}" + sensor="${sensor#*:}" + case "${sensor}" in '') + case "${cr}" in + 1) printf '%s:\r' "${label}";; + 0) printf '%s:\n' "${label}";; + esac + continue + esac + chip="${sensor%/*}" + element="${sensor##*/}" + print_sensor ${indent} "${label}" ${len} \ + "${chip}" "${chips}" "${element}" || return 1 + done + + return 0 +} + +main "${@}" |