infobar

Unixy status monitor
git clone git://wolog.xyz/infobar
Log | Files | Refs | README | LICENSE

infobar (7386B)


      1 #!/bin/sh
      2 
      3 # Copyright (C) Raymond Cole <rc@wolog.xyz>
      4 #
      5 # Licensed under GNU General Public License; either version 3 of the
      6 # License, or (at your option) any later version.  See the LICENSE file
      7 # for details.
      8 
      9 #!/bin/sh
     10 
     11 cleanup() {
     12 	set -- $(cat "$tmpdir"/pid/* 2>/dev/null)
     13 	[ $# -eq 0 ] || kill "$@"
     14 	rm -rf "$tmpdir"
     15 }
     16 
     17 humanize() {
     18 	_n="$1"
     19 	_b="$2"
     20 	shift 2
     21 	for _u in "$@"; do
     22 		[ "$_n" -ge "$_b" ] || break
     23 		_n=$(( (_n + _b / 2) / _b ))
     24 	done
     25 	echo "$_n$_u"
     26 }
     27 
     28 runinformer() {
     29 	_f="$1"; shift
     30 	[ -p "$tmpdir/fifo/$_f" ] || mkfifo "$tmpdir/fifo/$_f" || exit
     31 	[ -e "$tmpdir/pid/$_f" ] && kill "$(cat "$tmpdir/pid/$_f")"
     32 	"$@" >"$tmpdir/fifo/$_f" &
     33 	echo "$!" >"$tmpdir/pid/$_f"
     34 }
     35 
     36 updatebat() {
     37 	set -- "$(cat /sys/class/power_supply/BAT0/capacity)" "$bat"
     38 	for bat in '20:' '40:' '60:' '80:' '100:'; do
     39 		[ "$1" -lt "${bat%:*}" ] && break
     40 	done
     41 	bat="${bat#*:} $1%"
     42 	if grep -xFq Charging /sys/class/power_supply/BAT0/status; then
     43 		bat="$bat "
     44 	fi
     45 	[ "$bat" != "$2" ]; return  # return the result of the test
     46 }
     47 
     48 updateclk() {
     49 	case "$bar" in
     50 	*%C*) clk="$(date +'%a %b %d %T %Z %Y')" ;;
     51 	*) clk="$(date +'%a %b %d %H:%M')" ;;
     52 	esac
     53 	return 0
     54 }
     55 
     56 updatecpu() {
     57 	_o="$cpu"
     58 	set -- $(cat /proc/loadavg)
     59 	cpu=" $1"
     60 	case "$bar" in
     61 	*%P*)
     62 		set -- $(head -n 1 /proc/stat)
     63 		shift
     64 		_u=$(( $1 + $2 + $3 + $6 + $7 ))
     65 		_s=$(( _u + $4 + $5 ))
     66 		if [ -n "$cpuuse$cpusum" ]; then
     67 			cpu="$cpu $(( (_u - cpuuse) * 100 / (_s - cpusum) ))%"
     68 		fi
     69 		cpuuse="$_u"
     70 		cpusum="$_s"
     71 		if _f="$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)"; then
     72 			_t="$(humanize "$(( _f * 10 ))" 1000 '' K M G)"
     73 			_f="${_t%[[:digit:]]*}"
     74 			_f="${_f:-0}.${_t#$_f}"
     75 			cpu="$cpu ${_f}Hz"
     76 		fi
     77 	;;
     78 	esac
     79 	[ "$cpu" != "$_o" ]; return
     80 }
     81 
     82 updatemem() {
     83 	set -- $(free | sed -n '2{p;q}')
     84 	shift
     85 	_o="$mem"
     86 	_x="$(humanize "$(( $1 * 10 ))" 1024 Ki Mi Gi)"
     87 	_t="${_x%[[:digit:]]*}"
     88 	_t="${_t:-0}.${_x#$_t}B"
     89 	_x="$(humanize "$(( $2 * 10 ))" 1024 Ki Mi Gi)"
     90 	_u="${_x%[[:digit:]]*}"
     91 	_u="${_u:-0}.${_x#$_u}B"
     92 	mem=" ${_u}/${_t}"
     93 	[ "$mem" != "$_o" ]; return
     94 }
     95 
     96 updatenet() {
     97 	set -- "$net" $(ip route | sed -n 's/^default\( via \([^ ]*\)\)* dev \([^ ]*\).*/\3 \2/p;q')
     98 	if [ $# -ge 2 ] && grep -xFq up "/sys/class/net/$2/operstate"; then
     99 		case "$2" in
    100 		en*|eth*) net='' ;;
    101 		wl*) net='' ;;
    102 		ww*) net='' ;;
    103 		*) net="$2" ;;
    104 		esac
    105 		[ -n "$3" ] || net="$net "
    106 		case "$bar" in
    107 		*%N*)
    108 			case "$2" in
    109 			wl*)
    110 				_x="$(sed -n "s/^$2:"' *[^ ]* *[^ ]* *\([^.]*\).*/\1/p' /proc/net/wireless)"
    111 				net="$net ${_x}dBm"
    112 				;;
    113 			esac
    114 			_x="$(cat "/sys/class/net/$2/statistics/rx_bytes")"
    115 			[ -z "$netrx" ] || net="$net  $(humanize $(( _x - netrx )) 1024 B KiB MiB)"
    116 			netrx="$_x"
    117 			_x="$(cat "/sys/class/net/$2/statistics/tx_bytes")"
    118 			[ -z "$nettx" ] || net="$net  $(humanize $(( _x - nettx )) 1024 B KiB MiB)"
    119 			nettx="$_x"
    120 			;;
    121 		esac
    122 	else
    123 		case "$bar" in
    124 		*%N*) changebar %N %n ;;
    125 		esac
    126 		net=''
    127 	fi
    128 	[ "$net" != "$1" ]; return
    129 }
    130 
    131 updatevol() {
    132 	set -- $(amixer sget Master | sed -n 's/^.*\[\([0-9]\+\)%\].*\[\(on\|off\)\]/\1 \2/p;tL;d;:L;q')
    133 	if [ "$2" = on ]; then
    134 		for vol in '0:' '30:' '100:'; do
    135 			[ "$1" -le "${vol%:*}" ] && break
    136 		done
    137 		vol="${vol#*:} $1%"
    138 	else
    139 		vol=" $1%"
    140 	fi
    141 	return 0
    142 }
    143 
    144 setbar() {
    145 	bar="$1"
    146 	modules=
    147 	_o=
    148 	_s="$IFS"
    149 	IFS=' %'
    150 	for _x in $bar; do
    151 		modules="$_x $modules"
    152 		case "$_x" in
    153 		[[:upper:]]) _o="s${_o#s}" ;;
    154 		[bc]) _o="${_o%m}m" ;;
    155 		esac
    156 	done
    157 	IFS="$_s"
    158 	if [ "$ttopts" != "$_o" ]; then
    159 		runinformer t ticktack ${_o:+-$_o}
    160 		ttopts="$_o"
    161 	fi
    162 }
    163 
    164 changebar() {
    165 	setbar "${bar%%"$1"*}$2${bar#*"$1"}"
    166 }
    167 
    168 putbar() {
    169 	_s="$IFS"
    170 	IFS=%
    171 	for _x in $bar; do
    172 		_t="${_x%% *}"
    173 		case "${_t#%}" in
    174 		b)    _t="$bat" ;;
    175 		[Cc]) _t="$clk" ;;
    176 		M)    _t="$mem" ;;
    177 		[Nn]) _t="$net" ;;
    178 		[Pp]) _t="$cpu" ;;
    179 		v)    _t="$vol" ;;
    180 		esac
    181 		printf '%s' "$_t${_x##*[! ]}"
    182 	done
    183 	IFS="$_s"
    184 	echo
    185 }
    186 
    187 tmpdir="/tmp/infobar.$$"
    188 ttopts=
    189 bat=
    190 clk=
    191 cpu=
    192 cpuuse=
    193 cpusum=
    194 mem=
    195 net=
    196 netrx=
    197 nettx=
    198 vol=
    199 
    200 trap cleanup INT TERM EXIT
    201 mkdir "$tmpdir" && mkdir "$tmpdir/fifo" && mkdir "$tmpdir/pid" || exit
    202 
    203 # Some available modules:
    204 #
    205 # + %n - network connection (depends on the ip command)
    206 # + %v - volume and mutedness (depends on alsactl)
    207 # + %p - processor load over the last minute
    208 # + %b - battery percentage and charging state (depends on acpi_listen)
    209 # + %c - clock with the precision of minutes
    210 #
    211 # Among them %n and %v are updated upon relevant output of `ip monitor
    212 # route` and `alsactl monitor`, respectively.  %p, %b and %c are updated
    213 # upon every minute.  %b is in addition updated upon relevant output of
    214 # `acpi_listen`.
    215 #
    216 # The other modules have uppercase names and are updated every second:
    217 #
    218 # + %N - like %n but also shows signal strength (if wireless) and network traffic
    219 # + %P - like %p but also shows CPU usage and frequency
    220 # + %C - like %c but more detailed and shows seconds
    221 # + %M - memory usage
    222 #
    223 # Generally, the modules should be used in a specific format: Modules
    224 # should be separated by two or more spaces and nothing else.  No module
    225 # should appear more than once, and a lowercase module and its uppercase
    226 # counterpart shouldn't both be used.  The freedom lies mainly in deciding
    227 # which modules are included and in what order.
    228 
    229 setbar ' %n  %v  %p  %b  %c '
    230 
    231 # remove the %b module if there is no BAT0 (e.g. on desktop computer)
    232 [ -r /sys/class/power_supply/BAT0/capacity ] || changebar ' %b ' ''
    233 
    234 for x in $modules; do
    235 	case "$x" in
    236 	b)
    237 		runinformer a acpi_listen
    238 		updatebat
    239 		;;
    240 	[Cc])
    241 		updateclk
    242 		;;
    243 	M)
    244 		updatemem
    245 		;;
    246 	[Nn])
    247 		runinformer n ip monitor route
    248 		updatenet
    249 		;;
    250 	[Pp])
    251 		updatecpu
    252 		;;
    253 	v)
    254 		runinformer v alsactl monitor
    255 		updatevol
    256 		;;
    257 	esac
    258 done
    259 
    260 putbar
    261 
    262 fifolog - "$tmpdir"/fifo/* | while read -r src tok toks; do
    263 	case "$src" in
    264 	-)
    265 		for x in $modules; do
    266 			[ "$tok" -gt 1 ] || break
    267 			tok=$(( tok - 1 ))
    268 		done
    269 		butt="${toks%% *}"
    270 		case "$x" in
    271 		[Cc])
    272 			if [ "$butt" -eq 1 ]; then
    273 				if [ "$x" = c ]; then
    274 					changebar %c %C
    275 				else
    276 					changebar %C %c
    277 				fi
    278 				updateclk && putbar
    279 			fi
    280 			;;
    281 		[MPp])
    282 			if [ "$butt" -eq 1 ]; then
    283 				case "$bar" in
    284 				*'%P  %M'*)
    285 					changebar '%P  %M' %p
    286 					cpuuse=
    287 					cpusum=
    288 					updatecpu
    289 					putbar
    290 					;;
    291 				*%p*)
    292 					changebar %p '%P  %M'
    293 					updatecpu
    294 					updatemem
    295 					putbar
    296 					;;
    297 				esac
    298 			fi
    299 			;;
    300 		N)
    301 			if [ "$butt" -eq 1 ]; then
    302 				changebar %N %n
    303 				netrx=
    304 				nettx=
    305 				updatenet && putbar
    306 			fi
    307 			;;
    308 		n)
    309 			if [ "$butt" -eq 1 ]; then
    310 				changebar %n %N
    311 				updatenet && putbar
    312 			fi
    313 			;;
    314 		v)
    315 			if [ "$butt" -eq 3 ]; then
    316 				amixer -q set Master toggle
    317 				updatevol && putbar
    318 			elif [ "$butt" -eq 4 ]; then
    319 				amixer -q set Master 5%+
    320 				updatevol && putbar
    321 			elif [ "$butt" -eq 5 ]; then
    322 				amixer -q set Master 5%-
    323 				updatevol && putbar
    324 			fi
    325 			;;
    326 		esac
    327 		;;
    328 	a)
    329 		case "$bar" in
    330 		*%b*)
    331 			[ "$tok" = ac_adapter ] && updatebat && putbar
    332 			;;
    333 		esac
    334 		;;
    335 	[Nn])
    336 		case "$tok" in
    337 		Deleted|default)
    338 			updatenet && putbar
    339 			;;
    340 		esac
    341 		;;
    342 	t)
    343 		x="$tok$bar"
    344 		case "$x" in
    345 		[sm]*%b*) updatebat && putbar ;
    346 		esac
    347 		case "$x" in
    348 		m*%c*|[sm]*%C*) updateclk && putbar ;;
    349 		esac
    350 		case "$x" in
    351 		[sm]*%M*) updatemem && putbar ;;
    352 		esac
    353 		case "$x" in
    354 		[sm]*%N*) updatenet && putbar ;;
    355 		esac
    356 		case "$x" in
    357 		[sm]*%[Pp]*) updatecpu && putbar ;;
    358 		esac
    359 		;;
    360 	v)
    361 		updatevol && putbar
    362 		;;
    363 	!)
    364 		[ "$tok" == t ] || exit 1
    365 		;;
    366 	esac
    367 done