#! /bin/bash
+MSG_FS='|'
+
set -e
-consume() {
- pipe="$1"
- debug="$2"
- dir_bin="$3"
- prefixes_of_net_interfaces_to_show="$4"
- tail -f "$pipe" \
- | stdbuf -o L "$dir_bin"/khatus_controller \
- -v opt_debug="$debug" \
- -v opt_mpd_song_max_chars=10 \
- -v opt_prefixes_of_net_interfaces_to_show="$prefixes_of_net_interfaces_to_show"
+executable_name_of_cmd() {
+ basename "$(echo $1 | awk '{print $1; exit}')"
}
-spawn() {
+run_producer() {
pipe="$1"
- dir_bin="$2"
+ bin="$2"
cmd="$3"
- msg_head="$4"
- interval="$5"
- while true; do
- "$dir_bin"/$cmd | while read line; do
- echo "${msg_head} $line" > "$pipe"
+ executable_name="$4"
+ perf_log="$5"
+
+ if [ ! "$perf_log" = '' ]
+ then
+ # %S system time in seconds
+ # %U user time in seconds
+ # %e elapsed time in seconds
+ # %c context switches involuntary
+ # %w context switches voluntary
+ # %x exit code
+ time_fmt='%S %U %e %c %w %x'
+ time="/usr/bin/time -ao ${perf_log} -f "
+ time_sep=' '
+ else
+ time_fmt=''
+ time=''
+ time_sep=''
+ fi
+
+ ${time}"${time_fmt}"${time_sep}$bin/$cmd \
+ 2> >(
+ while read line
+ do
+ echo "ERROR${MSG_FS}${executable_name}${MSG_FS}$line" > "$pipe"
+ done \
+ ) \
+ | while read line
+ do
+ echo "OK${MSG_FS}${executable_name}${MSG_FS}$line" > "$pipe"
done
+ cmd_exit_code=${PIPESTATUS[0]}
+ if [ "$cmd_exit_code" -ne 0 ]
+ then
+ echo
+ "ERROR${MSG_FS}${executable_name}${MSG_FS}NON_ZERO_EXIT_CODE${MSG_FS}$cmd_exit_code" \
+ > "$pipe"
+ fi
+}
+
+fork_watcher() {
+ pipe="$1"
+ bin="$2"
+ cmd="$3"
+ executable_name=$(executable_name_of_cmd "$cmd")
+ run_producer "$pipe" "$bin" "$cmd" "$executable_name" &
+}
+
+fork_poller() {
+ interval="$1"
+ perf_log_dir="$2"
+ shift 2
+ pipe="$1"
+ bin="$2"
+ cmd="$3"
+
+ executable_name=$(basename "$(echo $cmd | awk '{print $1; exit}')")
+
+ if [ ! "$perf_log_dir" = '' ]
+ then
+ cmd="$3"
+ perf_log_file=${executable_name}.log
+ mkdir -p "$perf_log_dir"
+ perf_log_path="$perf_log_dir/$perf_log_file"
+ fi
+
+ while :
+ do
+ run_producer "$pipe" "$bin" "$cmd" "$executable_name" "$perf_log_path"
sleep "$interval"
done &
}
main() {
- # Defaults
- debug=0
- dir_bin="$HOME/bin"
- dir_data=$(mktemp -d)
- weather_station_id='KJFK'
- screen_brightness_device_name='acpi_video0'
- prefixes_of_net_interfaces_to_show='w' # comma-separated
- disk_space_device='/'
- disk_io_device='sda'
- thermal_zone=0
- fan_path='/proc/acpi/ibm/fan'
-
- interval_inp_datetime=1
- interval_inp_brightness=1
- interval_inp_weather=$(( 30 * 60)) # 30 minutes
- interval_inp_mpd_state=1
- interval_inp_mpd_song=1
- interval_inp_volume=1
- interval_inp_bluetooth=5
- interval_inp_net_wifi=5
- interval_inp_net_io=1
- interval_inp_disk_space=5
- interval_inp_disk_io=1
- interval_inp_loadavg=1
- interval_inp_temp=1
- interval_inp_fan=1
- interval_inp_mem=1
- interval_inp_energy=1
-
- # User-overrides
- long_options=''
- long_options+='debug'
- long_options+=',bin_dir:'
- long_options+=',data_dir:'
- long_options+=',weather_station:'
- long_options+=',screen_device:'
- long_options+=',prefixes_of_net_interfaces_to_show:'
- long_options+=',disk_space_device:'
- long_options+=',disk_io_device:'
- long_options+=',thermal_zone:'
- long_options+=',fan_path:'
- long_options+=',interval_inp_datetime:'
- long_options+=',interval_inp_brightness:'
- long_options+=',interval_inp_weather:'
- long_options+=',interval_inp_mpd_state:'
- long_options+=',interval_inp_mpd_song:'
- long_options+=',interval_inp_volume:'
- long_options+=',interval_inp_bluetooth:'
- long_options+=',interval_inp_net_wifi:'
- long_options+=',interval_inp_net_io:'
- long_options+=',interval_inp_disk_space:'
- long_options+=',interval_inp_disk_io:'
- long_options+=',interval_inp_loadavg:'
- long_options+=',interval_inp_temp:'
- long_options+=',interval_inp_fan:'
- long_options+=',interval_inp_mem:'
- long_options+=',interval_inp_energy:'
- OPTS=$(
- getopt \
- -o 'd' \
- -l $long_options \
- -- "$@"
+ declare -A opts=(
+ ["--dir_bin"]="$HOME/bin"
+ ["--dir_perf_logs"]=''
+ ["--file_pipe"]=$(mktemp)
+ ["--weather_station_id"]='KJFK'
+ ["--screen_brightness_device_name"]='acpi_video0'
+ ["--wifi_interface"]=''
+ ["--disk_space_device"]='/'
+ ["--disk_io_device"]='sda'
+ ["--thermal_zone"]=0
+ ["--fan_path"]='/proc/acpi/ibm/fan'
+ ["--pulseaudio_sink"]='0'
+ ["--interval_datetime"]=1
+ ["--interval_procs"]=1
+ ["--interval_brightness"]=1
+ ["--interval_weather"]=$(( 30 * 60)) # 30 minutes
+ ["--interval_mpd"]=1
+ ["--interval_volume"]=1
+ ["--interval_bluetooth"]=1
+ ["--interval_net_wifi"]=1
+ ["--interval_net_io"]=1
+ ["--interval_disk_space"]=1
+ ["--interval_disk_io"]=1
+ ["--interval_loadavg"]=1
+ ["--interval_temp"]=1
+ ["--interval_fan"]=1
+ ["--interval_mem"]=1
)
- eval set -- "$OPTS"
- while true
+ while :
do
- case "$1" in
- -d|--debug)
- debug=1
- shift
- ;;
- --bin_dir)
- dir_bin="$2"
- shift 2
- ;;
- --data_dir)
- dir_data="$2"
- shift 2
- ;;
- --weather_station)
- weather_station_id="$2"
- shift 2
- ;;
- --screen_device)
- screen_brightness_device_name="$2"
- shift 2
- ;;
- --prefixes_of_net_interfaces_to_show)
- prefixes_of_net_interfaces_to_show="$2"
- shift 2
- ;;
- --disk_space_device)
- disk_space_device="$2"
- shift 2
- ;;
- --disk_io_device)
- disk_io_device="$2"
- shift 2
- ;;
- --thermal_zone)
- thermal_zone="$2"
- shift 2
- ;;
- --fan_path)
- fan_path="$2"
- shift 2
- ;;
- --interval_inp_datetime)
- interval_inp_datetime="$2"
- shift 2
- ;;
- --interval_inp_brightness)
- interval_inp_brightness="$2"
- shift 2
- ;;
- --interval_inp_weather)
- interval_inp_weather="$2"
- shift 2
- ;;
- --interval_inp_mpd_state)
- interval_inp_mpd_state="$2"
- shift 2
- ;;
- --interval_inp_mpd_song)
- interval_inp_mpd_song="$2"
- shift 2
- ;;
- --interval_inp_volume)
- interval_inp_volume="$2"
- shift 2
- ;;
- --interval_inp_bluetooth)
- interval_inp_bluetooth="$2"
- shift 2
- ;;
- --interval_inp_net_wifi)
- interval_inp_net_wifi="$2"
- shift 2
- ;;
- --interval_inp_net_io)
- interval_inp_net_io="$2"
- shift 2
- ;;
- --interval_inp_disk_space)
- interval_inp_disk_space="$2"
- shift 2
- ;;
- --interval_inp_disk_io)
- interval_inp_disk_io="$2"
- shift 2
- ;;
- --interval_inp_loadavg)
- interval_inp_loadavg="$2"
- shift 2
- ;;
- --interval_inp_temp)
- interval_inp_temp="$2"
- shift 2
- ;;
- --interval_inp_fan)
- interval_inp_fan="$2"
- shift 2
- ;;
- --interval_inp_mem)
- interval_inp_mem="$2"
- shift 2
- ;;
- --interval_inp_energy)
- interval_inp_energy="$2"
- shift 2
- ;;
- --)
- shift
+ key="$1"
+ val="$2"
+ case "$key" in
+ '')
break
;;
+ * )
+ if [ -v opts["$key"] ]
+ then
+ if [ "$val" != "" ]
+ then
+ opts["$key"]="$val"
+ shift
+ shift
+ else
+ echo "Option $key requires an argument" >&2
+ exit 1
+ fi
+ else
+ echo "Unknown option: $key" >&2
+ exit 1
+ fi
esac
done
- pipe="$dir_data/khatus_data_pipe"
+ if [ "${opts['--wifi_interface']}" = '' ]
+ then
+ echo 'Please provide the required parameter: --wifi_interface' >&2
+ exit 1
+ fi
+
+ (
+ echo '=============================================='
+ echo "Khatus starting with the following parameters:"
+ echo '=============================================='
+ for param in ${!opts[@]}
+ do
+ echo "$param := ${opts[$param]}"
+ done \
+ | column -ts: \
+ | sort
+ echo '----------------------------------------------'
+ ) >&2
+
screen_brightness_device_path='/sys/class/backlight'
- screen_brightness_device_path+="/$screen_brightness_device_name"
+ screen_brightness_device_path+="/${opts['--screen_brightness_device_name']}"
- ( echo "Khatus starting with the following parameters:"
- ( echo " debug|= $debug"
- echo " dir_bin|= $dir_bin"
- echo " dir_data|= $dir_data"
- echo " pipe|= $pipe"
- echo " screen_brightness_device_name|= $screen_brightness_device_name"
- echo " screen_brightness_device_path|= $screen_brightness_device_path"
- echo " weather_station_id|= $weather_station_id"
- echo " prefixes_of_net_interfaces_to_show|= $prefixes_of_net_interfaces_to_show"
- echo " disk_space_device|= $disk_space_device"
- echo " disk_io_device|= $disk_io_device"
- echo " thermal_zone|= $thermal_zone"
- echo " fan_path|= $fan_path"
- ) | column -ts\|
- echo ''
- ) >&2
+ # Just shorthand
+ pipe="${opts['--file_pipe']}"
+ bin="${opts['--dir_bin']}"
+ perf="${opts['--dir_perf_logs']}"
- mkdir -p "$dir_data"
rm -f "$pipe"
mkfifo "$pipe"
cmd_sens_screen_brightness='khatus_sensor_screen_brightness'
cmd_sens_screen_brightness+=" $screen_brightness_device_path"
- cmd_sens_weather="khatus_sensor_weather $weather_station_id"
-
- cmd_sens_disk_space="khatus_sensor_disk_space $disk_space_device"
-
- cmd_sens_disk_io="khatus_sensor_disk_io $disk_io_device"
-
- cmd_sens_temperature="khatus_sensor_temperature $thermal_zone"
-
- cmd_sens_fan="khatus_sensor_fan $fan_path"
-
- # TODO: Redirect each worker's stderr to a dedicated log file
- spawn "$pipe" "$dir_bin" khatus_sensor_datetime 'in:DATE_TIME' $interval_inp_datetime
- spawn "$pipe" "$dir_bin" "$cmd_sens_screen_brightness" 'in:SCREEN_BRIGHTNESS' $interval_inp_brightness
- spawn "$pipe" "$dir_bin" "$cmd_sens_weather" 'in:WEATHER' $interval_inp_weather
- spawn "$pipe" "$dir_bin" khatus_sensor_mpd_state 'in:MPD_STATE' $interval_inp_mpd_state
- spawn "$pipe" "$dir_bin" khatus_sensor_mpd_song 'in:MPD_SONG' $interval_inp_mpd_song
- spawn "$pipe" "$dir_bin" khatus_sensor_volume 'in:VOLUME' $interval_inp_volume
- spawn "$pipe" "$dir_bin" khatus_sensor_bluetooth_power 'in:BLUETOOTH_POWER' $interval_inp_bluetooth
- spawn "$pipe" "$dir_bin" khatus_sensor_net_wifi_status 'in:NET_WIFI_STATUS' $interval_inp_net_wifi
- spawn "$pipe" "$dir_bin" khatus_sensor_net_addr_io 'in:NET_ADDR_IO' $interval_inp_net_io
- spawn "$pipe" "$dir_bin" "$cmd_sens_disk_space" 'in:DISK_SPACE' $interval_inp_disk_space
- spawn "$pipe" "$dir_bin" "$cmd_sens_disk_io" 'in:DISK_IO' $interval_inp_disk_io
- spawn "$pipe" "$dir_bin" khatus_sensor_loadavg 'in:LOAD_AVG' $interval_inp_loadavg
- spawn "$pipe" "$dir_bin" "$cmd_sens_temperature" 'in:TEMPERATURE' $interval_inp_temp
- spawn "$pipe" "$dir_bin" "$cmd_sens_fan" 'in:FAN' $interval_inp_fan
- spawn "$pipe" "$dir_bin" khatus_sensor_memory 'in:MEMORY' $interval_inp_mem
- spawn "$pipe" "$dir_bin" khatus_sensor_energy 'in:ENERGY' $interval_inp_energy
-
- consume \
- "$pipe" \
- "$debug" \
- "$dir_bin" \
- "$prefixes_of_net_interfaces_to_show"
+ cmd_sens_weather="khatus_sensor_weather $bin ${opts['--weather_station_id']}"
+ cmd_sens_disk_space="khatus_sensor_disk_space $bin ${opts['--disk_space_device']}"
+ cmd_sens_disk_io="khatus_sensor_disk_io $bin ${opts['--disk_io_device']}"
+ cmd_sens_temperature="khatus_sensor_temperature ${opts['--thermal_zone']}"
+ cmd_sens_fan="khatus_sensor_fan $bin ${opts['--fan_path']}"
+ cmd_sens_bluetooth="khatus_sensor_bluetooth_power $bin"
+ cmd_sens_mpd="khatus_sensor_mpd $bin"
+ cmd_sens_net_addr_io="khatus_sensor_net_addr_io $bin"
+ cmd_sens_volume="khatus_sensor_volume $bin"
+ cmd_sens_wifi="khatus_sensor_net_wifi_status $bin ${opts['--wifi_interface']}"
+ cmd_sens_loadavg="khatus_sensor_loadavg $bin"
+ cmd_sens_memory="khatus_sensor_memory $bin"
+
+ fork_watcher "$pipe" "$bin" "khatus_sensor_energy $bin"
+ fork_watcher "$pipe" "$bin" "khatus_sensor_devices $bin"
+ fork_poller "${opts['--interval_datetime']}" "$perf" "$pipe" "$bin" khatus_sensor_datetime
+ fork_poller "${opts['--interval_procs']}" "$perf" "$pipe" "$bin" "khatus_sensor_procs $bin"
+ fork_poller "${opts['--interval_brightness']}" "$perf" "$pipe" "$bin" "$cmd_sens_screen_brightness"
+ fork_poller "${opts['--interval_weather']}" "$perf" "$pipe" "$bin" "$cmd_sens_weather"
+ fork_poller "${opts['--interval_mpd']}" "$perf" "$pipe" "$bin" "$cmd_sens_mpd"
+ fork_poller "${opts['--interval_volume']}" "$perf" "$pipe" "$bin" "$cmd_sens_volume"
+ fork_poller "${opts['--interval_bluetooth']}" "$perf" "$pipe" "$bin" "$cmd_sens_bluetooth"
+ fork_poller "${opts['--interval_net_wifi']}" "$perf" "$pipe" "$bin" "$cmd_sens_wifi"
+ fork_poller "${opts['--interval_net_io']}" "$perf" "$pipe" "$bin" "$cmd_sens_net_addr_io"
+ fork_poller "${opts['--interval_disk_space']}" "$perf" "$pipe" "$bin" "$cmd_sens_disk_space"
+ fork_poller "${opts['--interval_disk_io']}" "$perf" "$pipe" "$bin" "$cmd_sens_disk_io"
+ fork_poller "${opts['--interval_loadavg']}" "$perf" "$pipe" "$bin" "$cmd_sens_loadavg"
+ fork_poller "${opts['--interval_temp']}" "$perf" "$pipe" "$bin" "$cmd_sens_temperature"
+ fork_poller "${opts['--interval_fan']}" "$perf" "$pipe" "$bin" "$cmd_sens_fan"
+ fork_poller "${opts['--interval_mem']}" "$perf" "$pipe" "$bin" "$cmd_sens_memory"
+
+ stdbuf -o L tail -f "$pipe"
}
main $@