#! /bin/sh #---------------------------------------------------------------------------- # master-diff-config - master file for config file camparison # # Creation: 2003-12-24 ap # Last Update: $Id$ # # Copyright (c) 2001-2011 Ansgar Puester, Ansgar.Puester(at)T-Online(dot).de # 2012-@@YEAR@@ the eisfair team, team(at)eisfair(dot)org # # 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 2 of the License, or # (at your option) any later version. #---------------------------------------------------------------------------- # # The following links have to be created # link type usage # template-diff-bb bb Show difference between two backup configurations # template-diff-cb cb Show difference between current and a backup configuration # template-diff-cd cd Show difference between current and default configuration # template-diff-db db Show difference between default and a backup configuration # # include eislib . /var/install/include/eislib # include function library . /var/install/bin/config_shlib # --------------------------------------------------------------------------- # halt(): debugging procedure # --------------------------------------------------------------------------- halt() { echo "+++ halt:" read a < /dev/tty } # --------------------------------------------------------------------------- # header_md(): header display # --------------------------------------------------------------------------- header_md() { clrhome mecho --info "${MD_TITLE}" mecho "${MD_SUBTITLE}" mecho } # --------------------------------------------------------------------------- # footer(): show footer # --------------------------------------------------------------------------- footer() { mecho mecho anykey } # --------------------------------------------------------------------------- # strip_file(): show footer # $1 input file # $2 output file # Input file should contain a valid eisfair-1 configuration # - all leading blanks will be erased # - all trailing blanks lines will be erased # - remaining blanks will be set to ~ # this will help to have _one_ varval eg. 'This~is~a~string~with~spaces' # - only lines starting with capital lettters will be used # - equal sign (=) will be set to space # - comments after varvals will be erased # \1 contains everything including first ' # \2 contains everything from this point to ' # => comment will be gone # Result is # varname 'value' # E.G. # SYSLOGD_LOG_COUNT '10' # --------------------------------------------------------------------------- strip_file() { in=$1 out=$2 cat ${in} | sed 's|^[[:blank:]]*||' | sed 's|[[:blank:]]*$||' | sed 's| |~|g' | grep '^[A-Z]' | sed 's|=| |' | sed "s|^\([^']*'\)\([^']*'\)\(.*\)|\1\2|"> ${out} chmod og-rw $out } # --------------------------------------------------------------------------- # echo_x(): show a value with maxumum length max_len # $1 line to display # --------------------------------------------------------------------------- echo_x() { val="$1 " mecho "${val:0:max_len}\c" } # --------------------------------------------------------------------------- # get_max_len(): calculate max_len # $left variables and values "left" file # $right variables and values "right" file # calculate maximum length # E.g. # START_NGINX 'yes' # NGINX_VAL '1024' # ########### => 10 # add place for 2 spaces # --------------------------------------------------------------------------- get_max_len() { max_len=0 while read var val do [ ${#var} -gt $max_len ] && max_len=${#var} done < $left while read var val do [ ${#var} -gt $max_len ] && max_len=${#var} done < $right max_len=$(expr $max_len + 2) } # --------------------------------------------------------------------------- # file_differ(): check if files differ # $left variables and values "left" file # $right variables and values "right" file # --------------------------------------------------------------------------- file_differ() { # sort files sort < $left > $left_sort sort < $right > $right_sort chmod og-rw $left_sort $right_sort # then check difference diff $left_sort $right_sort >/dev/null 2>&1 rc=$? return $rc } # --------------------------------------------------------------------------- # clean(): erase all intermediate files # --------------------------------------------------------------------------- clean() { rm -f $right rm -f $left rm -f $right_sort rm -f $left_sort rm -f $diff_file rm -f $both_ucont rm -f $both_cont } # --------------------------------------------------------------------------- # set_old(): save varname to o_varname / varval to o_varval # --------------------------------------------------------------------------- set_old () { o_varname=$varname o_varval=$varval } # --------------------------------------------------------------------------- # set_new(): save varname to n_varname / varval to n_varval # --------------------------------------------------------------------------- set_new () { n_varname=$varname n_varval=$varval } # --------------------------------------------------------------------------- # env_diff(): compare two files containing environment variables # $1 variables and values "left" file # $2 variables and values "right" file # --------------------------------------------------------------------------- env_diff() { # add 'new ' to every line of "left" file sed 's/.*/new &/' < $1 > $both_ucont # add 'old ' to every line of "right" file sed 's/.*/old &/' < $2 >> $both_ucont chmod og-rw $both_ucont # sort combined file: key 2, that is varname sort -k 2,2 < $both_ucont > $both_cont chmod og-rw $both_cont # indicator for new-line and old-line n_val=0 o_val=0 # read file while read ind varname varval do # new indicator if [ $ind = 'new' ] then if [ $n_val = 1 ] then echo "> $n_varname $n_varval" set_new else set_new n_val=1 fi fi # old indicator if [ $ind = 'old' ] then if [ $o_val = 1 ] then echo "$o_varname $o_varval <" set_old else set_old o_val=1 fi fi # both value are set if [ $n_val = 1 -a $o_val = 1 ] then if [ $n_varname = $o_varname ] then # identical names if [ "$n_varval" = "$o_varval" ] then echo "$o_varname $o_varval $n_varname $n_varval" else echo "$o_varname $o_varval | $n_varname $n_varval" fi o_val=0 n_val=0 else if [[ $n_varname < $o_varname ]] then echo "> $n_varname $n_varval" n_val=0 else echo "$o_varname $o_varval <" o_val=0 fi fi fi done < $both_cont # check remaining names if [ $n_val -eq 1 ] then echo "> $n_varname $n_varval" n_val=0 fi if [ $o_val -eq 1 ] then echo "$o_varname $o_varval <" o_val=0 fi } # --------------------------------------------------------------------------- # show_detail(): show details of the difference # --------------------------------------------------------------------------- show_detail() { # max len from variable get_max_len header_md row=5 max_row=9 gotoyx $row 1 #diff -y $left $right > $diff_file env_diff $left_sort $right_sort > $diff_file chmod og-rw $diff_file # read from file desciptor 9 to make ask work while read -u 9 line do set -- $line v1="$1" v2="$2" v3="$3" v4="$4" v5="$5" case $# in 3) if [ "$v1" = ">" ] then echo_x $v2 mecho "1: - undefined -" echo_x "" mecho '2: '$v3 | sed 's|~| |g' row=$(expr $row + 2) max_row=$(expr $max_row + 2) else if [ "$v3" = "<" ] then echo_x $v1 mecho '1: '$v2 | sed 's|~| |g' echo_x "" mecho "2: - undefined -" row=$(expr $row + 2) max_row=$(expr $max_row + 2) else mecho "Error(3): $line" row=$(expr $row + 1) max_row=$(expr $max_row + 1) fi fi ;; 4) if [ "$v2" != "$v4" ] then echo_x $v1 mecho '1: '$v2 | sed 's|~| |g' echo_x "" mecho '2: '$v5 | sed 's|~| |g' row=$(expr $row + 2) max_row=$(expr $max_row + 2) fi ;; 5) case $v3 in \|) echo_x $v1 mecho '1: '$v2 | sed 's|~| |g' echo_x "" mecho '2: '$v5 | sed 's|~| |g' row=$(expr $row + 2) max_row=$(expr $max_row + 2) ;; *) mecho "Error(5): $line" row=$(expr $row + 1) max_row=$(expr $max_row + 1) ;; esac ;; *) mecho "Error($#): $line" row=$(expr $row + 1) max_row=$(expr $max_row + 1) ;; esac # $SCROLL comes from env # show pages, but pages can not scroll back :-( if [ "${SCROLL}" = "no" ] then # use actual screensize if [ ${max_row} -gt ${_EISLIB_SCREENSIZE_Y} ] then max_row=9 mecho _ask_tmpfile=$(mktemp -t XXXXXXXXXXXXX) /var/install/bin/ask 'View' '' 'n=next page' "^$=Return" '0=Exit' > ${_ask_tmpfile} rc=${?} read answer < ${_ask_tmpfile} rm -f ${_ask_tmpfile} if [ ${rc} = 255 ] then answer=0 fi case "${answer}" in '') clean exit 0 ;; 0) clean exit 127 ;; n|N) header_md ${_ask_tmpfile} rc=${?} read answer < ${_ask_tmpfile} rm -f ${_ask_tmpfile} if [ ${rc} = 255 ] then answer=0 fi case "${answer}" in '') clean exit 0 ;; 0) clean exit 127 ;; esac fi } # --------------------------------------------------------------------------- # main # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # set title strings # --------------------------------------------------------------------------- MD_TITLE_bb='Show difference between two backup configurations' MD_TITLE_cb='Show difference between current and a backup configuration' MD_TITLE_cd='Show difference between current and default configuration' MD_TITLE_db='Show difference between default and a backup configuration' filename=`basename $0` # get package name from filename PACKAGE-diff-XY package=`echo $filename | sed "s|-diff-[cdb][cdb]$||"` type=`echo $filename | sed "s|^${package}-diff-||"` # if package is template # take package from $PACKAGE [ "$package" = 'template' ] && package="$PACKAGE" #debug echo "+++ TEST filename: $filename" #debug echo " PACKAGE: $PACKAGE" #debug echo " package: $package" #debug echo " type: $type" #debug read answ < /dev/tty case $type in cd) l_source=$configd/$package r_source=$defaultd/$package ;; cb) l_source=$configd/$package r_source="-" ;; db) l_source=$defaultd/$package r_source="-" ;; bb) l_source="-" r_source="-" ;; *) mecho "Error: illegal call $filename" footer exit ;; esac # set MD_TITLE and MD_SUBTITLE eval MD_TITLE="\$MD_TITLE_${type}" MD_SUBTITLE=" line 1: $r_source \n line 2: $l_source" # export for use in config_shlib (choose) export MD_TITLE export MD_SUBTITLE # r_source is still missing if [ $l_source = '-' ] then select_file case "${answer}" in '') exit 0 ;; 0) exit 127 ;; *) eval l_source='${bfile_'${answer}'}' omit_file=${l_source} ;; esac # change MD_SUBTITLE MD_SUBTITLE=" line 1: $r_source \n line 2: $l_source" fi # l_source is still missing if [ $r_source = '-' ] then select_file case "${answer}" in '') exit 0 ;; 0) exit 127 ;; *) eval r_source='${bfile_'${answer}'}' ;; esac # change MD_SUBTITLE MD_SUBTITLE=" line 1: $r_source \n line 2: $l_source" fi # make shure the file exists and is a regular file if [ $l_source != '-' -a ! -f $l_source ] then header_md mecho mecho --error "File $l_source does not exist." l_source='-' footer fi # make shure the file exists and is a regular file if [ $r_source != '-' -a ! -f $r_source ] then header_md mecho mecho --error "File $r_source does not exist." r_source='-' footer fi # O.K., we have two files if [ $l_source != '-' -a $r_source != '-' ] then header_md tmp_dir=/tmp right=$tmp_dir/right.$$ left=$tmp_dir/left.$$ diff_file=$tmp_dir/diff_file.$$ right_sort=$tmp_dir/right.srt.$$ left_sort=$tmp_dir/left.srt.$$ both_ucont=$tmp_dir/both.ucont.$$ both_cont=$tmp_dir/both.cont.$$ # strip both files for comparison strip_file ${l_source} $left strip_file ${r_source} $right mecho mecho "Files are compared without any comments. Unused leading and trailing" mecho "spaces are removed. The files are sorted alphabetically for all(!)" mecho "comparisons to get an optimal result." mecho "This means that the order of differencies shown is not the same" mecho "order than the variables appear in the configuration file." mecho if ! file_differ then mecho --error "The two files are different." mecho _ask_tmpfile=$(mktemp -t XXXXXXXXXXXXX) /var/install/bin/ask 'Show differencies' >${_ask_tmpfile} rc=${?} read answer < ${_ask_tmpfile} rm -f ${_ask_tmpfile} # handle CTRL-C if [ ${rc} = 255 ] then answer=no fi case "${answer}" in yes) show_detail ;; *) clean exit 0 ;; esac else mecho --info "The two files are identical." fi else header_md mecho --error "Too few files selected" fi clean footer exit # --------------------------------------------------------------------------- # end # ---------------------------------------------------------------------------