# BASH Interprocess communication demo by using simple "rendez-vous" file # # (C) 2011-2019 Felix Hauri - felix@f-hauri.ch # Licensed under terms of LGPL v3. www.gnu.org # v .02 BF_RENDEZVOUS=/dev/shm/foo back_func() { local -A MYGLOBAL local quiet exe [ "$1" = "-q" ] && quiet=true && shift [ -f $BF_RENDEZVOUS ] && . $BF_RENDEZVOUS if [ "$COMP_CWORD" ] ;then # Doing automatic bash completion there case $COMP_CWORD in 1) while read line; do [ -z "${line#*)}" ] && line=${line%)} && line=${line% | -[hgdrs]} && [ "$line" ] && [ -z "${line//*([a-z])}" ] && [ -z "${line##${COMP_WORDS[1]}*}" ] && COMPREPLY+=($line) done < <(declare -f back_func) ;; 2) case ${COMP_WORDS[1]} in get|-g ) for line in ${!MYGLOBAL[@]} ;do [ -z "${line##${COMP_WORDS[2]}*}" ] && COMPREPLY+=($line) done ;; start ) COMPREPLY=-g ;; esac ;; esac return fi case $1 in help | -h) echo "Usage: $FUNCNAME [-q] [start [-g N]|stop|restart|status|get|dump|help]" echo " -q Quiet" echo " -g N Start daemon, setting uptime_useGraph to N values" return ;; stop ) ### Stop by killing bf pid if back_func -q status;then kill ${MYGLOBAL["backFunc_pid"]} && return fi $quiet echo "No process killed." return 1 ;; start ) ### Start in background if back_func -q status ;then $quiet \ echo "Process ${MYGLOBAL["backFunc_pid"]} already running." return 1 fi shift ( back_func start_real $@ & ) /dev/null 2>/dev/null return $? ;; status | -s ) if [ "${MYGLOBAL["backFunc_running"]}" = "yes" ] && [ -d /proc/${MYGLOBAL[backFunc_pid]} ] && exe=$(readlink /proc/${MYGLOBAL[backFunc_pid]}/exe) && [ "${exe##*/}" = "bash" ] && [ -z "$(/bin/ls /proc/${MYGLOBAL[backFunc_pid]}/fd)" ] ; then $quiet printf "Background loop function (%s) is running.\n" \ ${MYGLOBAL[backFunc_pid]} return 0 fi $quiet echo "Background loop function is not running." return 1 ;; restart | -r ) back_func ${quiet:+-q} stop back_func -q status && inotifywait -t 3 -e close -q $BF_RENDEZVOUS >/dev/null back_func ${quiet:+-q} start return 1 ;; dump | -d ) ### dump all variables sort <( paste -d ' ' <( printf "%-16s\n" ${!MYGLOBAL[@]} ) <( printf "%20s\n" "${MYGLOBAL[@]}")) return ;; get | -g ) ### return only 1 field from snapshot. printf ${3+-v} $3 "%s" "${MYGLOBAL[$2]}" return ;; start_real ) shift;; * ) return 1 ;; ### Exit if $1 <> 'start_real' esac ### Close STDIN, STDOUT, STDERR and even other local _i for _i in $(/bin/ls /proc/$$/fd);do eval "exec $_i>&-" done unset MYGLOBAL declare -A MYGLOBAL MYGLOBAL["backFunc_pid"]=$BASHPID MYGLOBAL["backFunc_running"]=yes printf -v MYGLOBAL["backFunc_start"] "%(%F %T)T" -1 [ "$1" = "-g" ] && [ "$2" ] && (($2>2)) && (($2<999999)) && printf -v MYGLOBAL["uptime_graph_val"] %d $2 || printf -v MYGLOBAL["uptime_graph_val"] %d 60 ### Prepare to update ``running'' and add ``end'' fields when exit trap " . $BF_RENDEZVOUS; printf -v MYGLOBAL['backFunc_end'] '%(%F %T)T' -1; MYGLOBAL['backFunc_running']=no declare -p MYGLOBAL > $BF_RENDEZVOUS exit 0 " 0 2 3 6 9 15 ### Main loop begin here MYGLOBAL["cpu_numcores"]=$(grep -c ^processor /proc/cpuinfo) while :;do ((MYGLOBAL["backFunc_count"]++)) local old_utm=${MYGLOBAL["uptime_up"]//.} \ old_idl=${MYGLOBAL["uptime_idle"]//.} prct read MYGLOBAL["uptime_up"] MYGLOBAL["uptime_idle"] ${MYGLOBAL["uptime_graph_val"]} )) && MYGLOBAL["uptime_useGraph"]=${MYGLOBAL["uptime_useGraph"]#* } prct=000$(( 100000 - 100000 * ${MYGLOBAL["uptime_idle"]//.} / ${MYGLOBAL["uptime_up"]//.} / ${MYGLOBAL["cpu_numcores"]} )) printf -v MYGLOBAL["uptime_usage"] "%.2f" \ ${prct:0:${#prct}-3}.${prct:${#prct}-3} IFS=\ / read $BF_RENDEZVOUS sleep 1 done } complete -F back_func{,} lastMinuteGraph() { local vars x y path outFile exe foo png opt delay OPTIND outFile=/dev/shm/lastMinute width=640 height=480 while getopts "hlpd:o:W:H:" opt;do case $opt in h ) echo "Usage: $FUNCNAME [-l|-d DELAY] [-p] [-o FILE]"; echo " -l loop" echo " -d N delay (implie -l)" echo " -p PNG output (default to SVG)" echo " -o File Output file (default '$outFile')" echo " -W N Width of graphic (default $width)" echo " -H N Height of graphic (default $height)" return ;; l ) delay=${delay:-1} ;; p ) png=-p ;; d ) delay=$OPTARG ;; o ) outFile=${OPTARG%.??g} ;; W ) width=$OPTARG ;; H ) height=$OPTARG ;; * ) echo >&2 "$FUNCNAME Error: $opt not understand."; return 1 ;; esac;done [ "$delay" ] && { while ! read -n 1 -t $delay foo ;do lastMinuteGraph $png -o $outFile done return 0 } [ -z "$png" ] && exe="cat >$outFile.svg" || \ exe="inkscape -z --export-png=$outFile.png >/dev/null 2>&1 /dev/stdin" back_func get uptime_useGraph vars path="M0,0 L" x=0 for y in $vars ;do path+=" $((x++*3)) $y $((3*x)) $y" done path+=" L $((3*x)),0 z" eval $exe <<-endOfSvgFile endOfSvgFile }