#!/bin/bash
##   BISMON  ---- simple analysis of the Dash shell
##   Copyright ©  2021 CEA (Commissariat à l'énergie atomique et aux énergies alternatives)
##   contributed by Basile Starynkevitch (working at CEA, LIST, France)
##   <basile@starynkevitch.net> or <basile.starynkevitch@cea.fr>
##
##   This program is free software: you can redistribute it and/or modify
##   it under the terms of the GNU General Public License as published by
##   the Free Software Foundation, either version 3 of the License, or
##   (at your option) any later version.
##
##   This program is distributed in the hope that it will be useful,
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##   GNU General Public License for more details.
##
##   You should have received a copy of the GNU General Public License
##   along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##   ----
##   Contact me (Basile Starynkevitch) by email
##   basile@starynkevitch.net and/or basile.starynkevitch@cea.fr
##   -----------

### the Dash shell is from git.kernel.org/pub/scm/utils/dash/dash.git
### we want to analyze its version 0.5.11.4 or similar

### we conventionally use environment variables $BISMONDASH_* for
### Dash-Analyze specific settings, and $BISMON for Bismon specific
### settings

if [ -f $HOME/.bismon-dash-analyze ]; then
    ##|## that ~/.bismon-dash-analyze could export....
    ##|##    BISMONDASH_SOURCE_DASH - source directory for dash, with dash.1
    ##|##
    ##|##    BISMON_GCC - the GCC compiler compiling Bismon
    ##|##        €.g. BISMON_GCC=/usr/local/bin/host-gcc-11
    ##|##
    ##|##    BISMON_MAKE - the make (e.g. GNU make) program
    ##|##        €.g. BISMON_MAKE=/usr/bin/remake
    ##|##
    ##|##    BISMON_MAKE_FLAGS - the make options
    ##|##        €.g. BISMON_MAKE_FLAGS=-j3
    ##|##
    ##|##    BISMON_WEB_BASE for the base URL interfacing Bismon while
    ##|##    it is running
    ##|##        €.g. BISMON_WEB_BASE=localhost:8087
    ##|##
    ##|##    BISMON_GCC_PLUGIN is the shared object for our GCC plugin
    ##|##        €.g  BISMON_GCC_PLUGIN=/tmp/bismon-gcc-plugin.so
    ##|##
    ##|##    BISMON_PLUGIN_ASMOUT is used by our
    ##|##    ./build-gcc10-metaplugin.sh script and could contain some *.s
    ##|##    file for the assembler file of that plugin.
    ##|##        €.g  BISMON_PLUGIN_ASMOUT=/tmp/gcc10_metaplugin_BMGCC.s
    ##|##
    ##|##    BISMONDASH_PROJECT is the name of the Bismon project for
    ##|##    this analysis.
    ##|##        €.g. BISMONDASH_PROJECT=dash_project
    ##|##
    ##|##    BISMONDASH_PIDFILE is the name of the textual file
    ##|##    containing the pid of Bismon for this analysis.
    ##|##        €.g. BISMONDASH_PIDFILE=$HOME/.bismondash_pid
    ##|##
    ##|##   BISMONDASH_GCC is the GCC compiler for compiling Dash shell
    ##|##   by default is it BISMON_GCC, when not given
    ##|##        €.g. BISMONDASH_GCC=/usr/local/bin/gcc-10
    ##|##
    ##|##
    ##|##    BISMON_COOKIE_FILE, if given, contain the Bismon HTTP cookie
    ##|##        €.g. BISMON_COOKIE_FILE=/tmp/bismon_dashcokkie
    ##|##
    ##|##
    source  $HOME/.bismon-dash-analyze
fi

### the default source location of Dash (containing dash.1) in
### practice we have a symlink similar to
###    /usr/src/Shell/dash -> /usr/src/Shell/dash-0.5.11.4
if [ -z "$BISMONDASH_SOURCE_DASH" ]; then
    export BISMONDASH_SOURCE_DASH=/usr/src/Shell/dash
fi

if [ ! -f "$BISMONDASH_SOURCE_DASH/src/dash.1" ]; then
    echo $0: no src/dash.1 file in BISMONDASH_SOURCE_DASH= $BISMONDASH_SOURCE_DASH > /dev/stderr
    exit 1
fi


## BISMON_GCC is the GCC compiler compiling Bismon
if [ -z "$BISMON_GCC" ]; then
    export BISMON_GCC=/usr/bin/gcc-10
fi


## BISMON_WEB_BASE is for the URL interfacing Bismon while it is running
if [ -z "$BISMON_WEB_BASE" ]; then
    export BISMON_WEB_BASE=localhost:8086
fi

## BISMONDASH_PROJECT is the name of the project for Dash, as known to Bismon
## and to GCC metaplugins
if [ -z "$BISMONDASH_PROJECT" ]; then
    export BISMONDASH_PROJECT=dash_bismon_project
fi

## BISMONDASH_GCC is the GCC compiler compiling Dash
if [ -z "$BISMONDASH_GCC" ]; then
    export BISMONDASH_GCC=$BISMON_GCC
fi


## BISMON_GCC_PLUGIN is the shared object for our plugin
if [ -z "$BISMON_GCC_PLUGIN" ]; then
    export BISMON_GCC_PLUGIN=$(realpath gccplugins/gcc10_metaplugin_BMGCC.so)
fi

## BISMONDASH_PIDFILE is the name of the filepath containing the pid of Bismon
if [ -z "$BISMONDASH_PIDFILE" ]; then
    export BISMONDASH_PIDFILE=/tmp/bismondash_pidfile
fi

### if file "$BISMONDASH_PIDFILE" exists and contains a running pid, kill it
if [ -f "$BISMONDASH_PIDFILE" ]; then
    declare -i bismon_pid=$(/bin/cat "$BISMONDASH_PIDFILE")
    if [ $bismon_pid -gt 0 -a -d /proc/$bismon_pid/ ]; then
	kill -QUIT $bismon_pid
	sleep 0.5
	if [ -d /proc/$bismon_pid/ ] ; then
	    kill -TERM $bismon_pid
	fi
    fi
else
    pkill --exact --full --signal QUIT bismon || true
fi



### the generated header file _bm_config.h should exist, since it has been created by running successfully the ./Configure script
if [ ! -f _bm_config.h ]; then
    printf "%s: missing _bm_config.h in directory %s\n" $0 $(pwd) > /dev/stderr
    printf "... Please run the ./Configure script in this directory %s\n" $(pwd) > /dev/stderr
    exit 1
fi

declare dash_analysis_need_bismon_build
if [ ! -x bismon ]; then
    dash_analysis_need_bismon_build=yes
else
    for bmsrc in [a-z]*BM.c ; do
	if [ $bmsrc -nt bismon ] ; then
	    dash_analysis_need_bismon_build=yes
	fi
    done
fi

if [ -n "$dash_analysis_need_bismon_build" ]; then
    ### our Build script is using shell variables like BISMON_MAKE
    ### (e.g. the GNU make) BISMON_MAKE_FLAGS
    ./Build
fi

declare -a bismon_dash_args

for f in "$@"; do
    case "$f" in
	--bismon*) bismon_dash_args=($bismon_dash_args $f);;
	--dash-source=*) export BISMONDASH_SOURCE_DASH=$(echo $f | /bin/sed -e s/--dash-source=//);;
	--asm) export BISMON_PLUGIN_ASMOUT=/tmp/gcc10_metaplugin_BMGCC.s;;
	--gcc=*) export BISMON_GCC=$(echo $f | /bin/sed -e s/--gcc=//);;
    esac
done


# https://serverfault.com/a/477506
if [ ${#bismon_dash_args[@]} -eq 0 ]; then
    bismon_dash_args=( --bismon-web-base=$BISMON_WEB_BASE --bismon-project-name=$BISMON_DASH_PROJECT --bismon-pid-file=$BISMONDASH_PIDFILE )
fi


echo "$0:" bismon arguments $bismon_dash_args in $(pwd) > /dev/stderr

echo "$0:" Dash shell source $BISMONDASH_SOURCE_DASH > /dev/stderr


#### check existence of needed GCC plugin files

if [ ! -d gccplugins/ ]; then
    echo "$0:" missing gccplugins/ directory in $(pwd) > /dev/stderr
    exit 1
fi

if [ ! -f gccplugins/gcc10_metaplugin_BMGCC.cc ]; then
    echo  "$0:" missing gccplugins/gcc10_metaplugin_BMGCC.cc in $(pwd) > /dev/stderr
    exit 1
fi

if [ ! -f gccplugins/gcc10_metaplugin_BMGCC.hh ]; then
    echo  "$0:" missing gccplugins/gcc10_metaplugin_BMGCC.hh in $(pwd) > /dev/stderr
    exit 1
fi

if [ ! -x gccplugins/build-gcc10-metaplugin.sh ]; then
    echo  "$0:" missing or bad gccplugins/build-gcc10-metaplugin.sh script in $(pwd) > /dev/stderr
    exit 1
fi



################################################################
########## start Bismon

if [ ! -x bismon ]; then
    echo "$0:" cannot start missing Bismon > /dev/stderr
    exit 1
fi

printf "\n\n\n ==== %s: starting Bismon ======\n\n" "$0"
echo '#° ./bismon' $bismon_dash_args
./bismon $bismon_dash_args &
export BISMON_PID=$!

sleep 1.8

printf "\n%s: Bismon pid is %s\n" $0 $BISMON_PID

netstat --tcp --all --numeric  --program

sleep 0.5

########## now Bismon is running
################################################################


### notice that the ./build-gcc10-metaplugin.sh may use the
### BISMON_PLUGIN_ASMOUT environment variable. For example, set it
### with export BISMON_PLUGIN_ASMOUT=/tmp/gcc10_metaplugin_BMGCC.s

### on some Debian, there is a bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=980609
pushd gccplugins
if [ -f gcc10_metaplugin_BMGCC.so ]; then
    ## force recompilation of plugin if older than plugin source code
    if [ gcc10_metaplugin_BMGCC.so -ot gcc10_metaplugin_BMGCC.cc ]; then
	/bin/rm gcc10_metaplugin_BMGCC.so
    elif [ gcc10_metaplugin_BMGCC.so -ot gcc10_metaplugin_BMGCC.hh ]; then
	/bin/rm gcc10_metaplugin_BMGCC.so
    fi
fi
### Notice: the build-gcc10-metaplugin.sh script cares about a BISMON_PLUGIN_ASMOUT shell variable...
./build-gcc10-metaplugin.sh
popd

if [ ! -f "$BISMON_GCC_PLUGIN" ]; then
    printf "%s: missing GCC plugin for Bismon (maybe set %s shell variable)\n" "$0" 'BISMON_GCC_PLUGIN' > /dev/stderr
    exit 1
fi

export BISMON_GCC_NAME_PLUGIN=$(basename "$BISMON_GCC_PLUGIN" .so)


### compile some given *.c file under $BISMONDASH_SOURCE_DASH/src/
function compile_dash_c_file () {
    $BISMONDASH_GCC -c -DHAVE_CONFIG_H -I. -I..  -include ../config.h \
		    -DBSD=1 -DSHELL -Wall -Wextra -O -g \
		    -fplugin=$BISMON_GCC_PLUGIN \
		    $1
    if [ $? -gt 0 ]; then
	printf '%s: failed to compile dash C file %s\n' $0 $1 > /dev/stderr
	exit 1
    fi
    sleep 0.1
}


if [ -z "$BISMONDASH_GCC" ]; then
    printf '%s: cannot compile Dash source files, since missing $BISMONDASH_GCC in %s\n' $0 $(pwd) > /dev/stderr
    exit 1
fi

################ compile Dash C files
pushd $BISMONDASH_SOURCE_DASH/src/

compile_dash_c_file alias.c
compile_dash_c_file arith_yacc.c
compile_dash_c_file arith_yylex.c
compile_dash_c_file cd.c
compile_dash_c_file error.c
compile_dash_c_file eval.c
compile_dash_c_file exec.c
compile_dash_c_file expand.c
compile_dash_c_file histedit.c
compile_dash_c_file input.c
compile_dash_c_file jobs.c
compile_dash_c_file mail.c
compile_dash_c_file main.c
compile_dash_c_file memalloc.c
compile_dash_c_file miscbltin.c
compile_dash_c_file mystring.c
compile_dash_c_file options.c
compile_dash_c_file parser.c
compile_dash_c_file redir.c
compile_dash_c_file show.c
compile_dash_c_file trap.c
compile_dash_c_file output.c
compile_dash_c_file system.c
compile_dash_c_file var.c
compile_dash_c_file builtins.c
compile_dash_c_file init.c
compile_dash_c_file nodes.c
compile_dash_c_file signames.c
compile_dash_c_file syntax.c
compile_dash_c_file bltin/printf.c
compile_dash_c_file bltin/test.c
compile_dash_c_file bltin/times.c
popd

printf "%s: sleeping five seconds (pid %s)\n" $0 $$
sleep 5


printf "%s: incomplete script (pid %s)\n" $0 $$
exit 1
################################# incomplete script Dash-Analyze

