#!@l_prefix@/lib/openpkg/bash --noprofile
##
##  @l_prefix@/etc/rc -- Run-Command Handling for OpenPKG Hierarchy
##  Copyright (c) 2000-2003 Cable & Wireless Deutschland GmbH
##  Copyright (c) 2000-2003 The OpenPKG Project <http://www.openpkg.org/>
##  Copyright (c) 2000-2003 Ralf S. Engelschall <rse@engelschall.com>
##
##  Permission to use, copy, modify, and distribute this software for
##  any purpose with or without fee is hereby granted, provided that
##  the above copyright notice and this permission notice appear in all
##  copies.
##
##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
##  SUCH DAMAGE.
##

#   program name, version and date
progname="rc"
progvers="1.0.10"
progdate="21-Feb-2003"

#   helper variables
NL="
"

##
##  command line option parsing
##

#   default parameters
verbose=0
help=0
print=0
eval=0
config=0
query=0
raw=0
rcdir="@l_prefix@/etc/rc.d"

#   iterate over argument line
while [ $# -gt 0 ]; do
    opt=$1
    case $opt in
        -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
           *) arg='' ;;
    esac
    case $opt in
        -v|--verbose ) verbose=1     ;;
        -h|--help    ) help=1        ;;
        -p|--print   ) print=1       ;;
        -e|--eval    ) eval=1        ;;
        -c|--config  ) config=1      ;;
        -q|--query   ) query=1       ;;
        -r|--raw     ) raw=1         ;;
        --rcdir=*    ) rcdir=$arg    ;;
        -*           ) help="Invalid option \`$opt'"; break ;;
        *            ) break         ;;
    esac
    shift
done

#   determine path to rc.conf
rcconf="`echo $rcdir | sed -e 's;/rc.d$;/rc.conf;'`"
rcfunc="`echo $rcdir | sed -e 's;/rc.d$;/rc.func;'`"

#   error or usage message
if [ ".$help" != .0 ]; then
    if [ ".$help" != ".Usage" ]; then
        echo "$progname:ERROR: $help" 1>&2
    fi
    echo "Usage: $progname [-v|--verbose] [-h|--help]" 1>&2
    echo "       [-p|--print] [-e|--eval] [-c|--config] [-q|--query] [-r|--raw]" 1>&2
    echo "       <package> <command> [<command> ...]"  1>&2
fi

#   extend run-time environment with our local tools (shtool, rpmtool, etc)
PATH="@l_prefix@/bin:$PATH"
PATH="@l_prefix@/sbin:$PATH"
PATH="@l_prefix@/lib/openpkg:$PATH"

#   set a reasonable temporary location
tmpdir="/tmp"
tmpfile="$tmpdir/rc.$$.tmp"
TMPDIR="$tmpdir";  export TMPDIR
TEMPDIR="$tmpdir"; export TEMPDIR

#   handle --query option
if [ ".$query" = .1 ]; then
    var="$1"
    scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;"`
    rm -f $tmpfile
    touch $tmpfile
    for s_name in $scripts; do
        sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
    done
    . $tmpfile
    . $rcconf
    eval "echo \${$var}"
    rm -f $tmpfile
    exit 0
fi

#   handle --config option
if [ ".$config" = .1 ]; then
    scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;"`
    rm -f $tmpfile
    touch $tmpfile
    for s_name in $scripts; do
        sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
    done
    vars=""
    . $tmpfile
    OIFS="$IFS"; IFS="$NL"
    for assign in `egrep '[ 	]*[a-zA-Z_][a-zA-Z_0-9]*=' $tmpfile | sort`; do
        var=`echo "$assign" | sed -e 's;^[ 	]*\([a-zA-Z_][a-zA-Z_0-9]*\)=.*;\1;'`
        vars="$vars $var"
        eval "${var}_def=\"\$$var\""
    done
    IFS="$OIFS"
    . $rcconf
    if [ ".$raw" = .0 ]; then
        begin_bold=`@l_prefix@/lib/openpkg/shtool echo -e '%B'`
        end_bold=`@l_prefix@/lib/openpkg/shtool echo -e '%b'`
    else
        begin_bold=""
        end_bold=""
    fi
    echo "${begin_bold}Configuration Variable   Effective Value              Default Value${end_bold}"
    echo "------------------------ ------------------------- -- -------------------------"
    for var in . $vars; do
        test ".$var" = .. && continue
        eval "val=\"\$$var\""
        eval "def=\"\$${var}_def\""
        tag="!="
        begin="$begin_bold"
        end="$end_bold"
        if [ ".$val" = ".$def" ]; then
            tag="=="
            begin=""
            end=""
        fi
        echo dummy | awk '{ printf("%s%-24s %-25s %s %-25s%s\n", begin, var, val, tag, def, end); }' \
            begin="$begin" var="$var" tag="$tag" val="\"$val\"" def="\"$def\"" end="$end"
    done
    rm -f $tmpfile
    exit 0
fi

#   determine script(s) to use
if [ $# -lt 2 ]; then
    echo "$0:ERROR: no package and command(s) specified" 1>&2
    exit 1
fi
scripts=`echo "$1" | sed -e 's;^.*rc\.;;'`
shift
if [ ".$scripts" = ".all" ]; then
    . $rcconf
    case "$openpkg_runall" in
        [Nn][Oo] | [Ff][Aa][Ll][Ss][Ee] | [Oo][Ff][Ff] | 0 ) exit 0 ;;
    esac
    scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;"`
else
    if [ ! -f "$rcdir/rc.$scripts" ]; then
        echo "$0:ERROR: script \`$rcdir/rc.$scripts' not found" 1>&2
        exit 1
    fi
fi

#   determine current run-time user
user="`(id -un) 2>/dev/null`"
if [ ".$user" = . ]; then
    user="`(whoami) 2>/dev/null | awk '{ printf("%s", $1); }'`"
    if [ ".$user" = . ]; then
        user="`(who am i) 2>/dev/null | awk '{ printf("%s", $1); }'`"
        if [ ".$user" = . ]; then
            user="$LOGNAME"
        fi
        if [ ".$user" = . ]; then
            echo "$0:ERROR: unable to determine current username" 1>&2
            if [ ".$user" = . ]; then
                user="$USER"
                if [ ".$user" = . ]; then
                    echo "$0:ERROR: unable to determine current username" 1>&2
                    exit 1
                fi
            fi
            exit 1
        fi
    fi
fi

#   iterate over the commands
cmds="$*"
for cmd in $cmds; do

    #   find scripts which contain the command and determine
    #   their individual user/prio settings
    list=''
    for s_name in $scripts; do
        enable=yes

        #   check script options
        shebangline=`head -1 $rcdir/rc.$s_name | grep "^#!rc"`
        if [ ".$shebangline" != . ]; then
            shebangopts=`echo "$shebangline" | sed -e "s;^#!rc *;;"`
            set -- $shebangopts;
            prev=''
            for opt
            do
                if [ ".$prev" != . ]; then
                    opt="$prev$opt"
                    prev=''
                fi
                case $opt in
                    -*=*       ) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
                    -[a-zA-Z]* ) arg=`echo "$opt" | sed 's/^-[a-zA-Z0-9]//'`    ;;
                              *) arg='' ;;
                esac
                case $opt in
                    -e|--enable  ) enable=yes ;;
                    -d|--disable ) enable=no  ;;
                    *          ) echo "$0:ERROR: invalid option \`$opt' in \`$rcdir/rc.$s_name:#!rc'"; break ;;
                esac
                shift
            done
        fi

        #   check whether command exists in script
        cmdline=`grep "^%$cmd" $rcdir/rc.$s_name`
        if [ ".$cmdline" != . ]; then
            cmdopts=`echo "$cmdline" | sed -e "s;^%$cmd *;;"`
            s_user=$user
            s_prio=500
            set -- $cmdopts;
            prev=''
            for opt
            do
                if [ ".$prev" != . ]; then
                    opt="$prev$opt"
                    prev=''
                fi
                case $opt in
                    -*=*       ) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
                    -[a-zA-Z]* ) arg=`echo "$opt" | sed 's/^-[a-zA-Z0-9]//'`    ;;
                              *) arg='' ;;
                esac
                case $opt in
                    -u|-p         ) prev=$opt    ;;
                    -e|--enable   ) enable=yes   ;;
                    -d|--disable  ) enable=no    ;;
                    -u*|--user=*  ) s_user=$arg  ;;
                    -p*|--prio=*  ) s_prio=$arg  ;;
                    *             ) echo "$0:ERROR: invalid option \`$opt' in \`$rcdir/rc.$s_name'"; break ;;
                esac
                shift
            done
            if [ ".$s_user" != ".$user" -a ".$user" != ".root" ]; then
                echo "$0:ERROR: require root privileges to run \`$rcdir/rc.$s_name:$cmd' as user \`$s_user'" 1>&2
                exit 1
            fi
            #   skip script if disabled
            if [ ".$enable" != .yes ]; then
                continue
            fi
            list="$list,$s_prio:$s_name:$s_user"
        fi
    done

    #   execute/print the scripts in order
    if [ ".$print" = .1 -o ".$eval" = .1 ]; then
        rm -f $tmpfile
        touch $tmpfile
        if [ ".$verbose" = .1 ]; then
            echo "set -x" >>$tmpfile
        fi
    fi
    for entry in `echo $list | tr ',' '\012' | sort -n`; do
        test ".$entry" = . && continue
        eval `echo $entry | sed -e 's%^[0-9]*:\(.*\):\(.*\)$%s_name="\1"; s_user="\2"%'`
        if [ ".$verbose" = .1 ]; then
            echo "$0: executing $rcdir/rc.$s_name [%$cmd] as user $s_user" 1>&2
        fi
        if [ ".$print" = .1 -o ".$eval" = .1 ]; then
            echo ". $rcfunc" >>$tmpfile
            l_scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;"`
            for l_name in $l_scripts; do
                sed <$rcdir/rc.$l_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
            done
            echo ". $rcconf" >>$tmpfile
            sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d'
            sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d'
            continue
        fi
        rm -f $tmpfile
        touch $tmpfile
        if [ ".$verbose" = .1 ]; then
            echo "set -x" >>$tmpfile
        fi
        echo ". $rcfunc" >>$tmpfile
        l_scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;"`
        for l_name in $l_scripts; do
            sed <$rcdir/rc.$l_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
        done
        echo ". $rcconf" >>$tmpfile
        sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d'
        sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d'
        sh='sh'
        if [ ".$user" != ".$s_user" ]; then
            su - $s_user -c "PATH=\"$PATH\"; sh $tmpfile"
            rc=$?
        else
            sh $tmpfile
            rc=$?
        fi
        if [ $rc -ne 0 ]; then
            echo "$0:WARNING: script \`$rcdir/rc.$s_name:$cmd' returned non-null ($#) return code" 1>&2
        fi
    done
    if [ ".$print" = .1 ]; then
        cat $tmpfile
    elif [ ".$eval" = .1 ]; then
        echo ". $tmpfile; rm -f $tmpfile 2>/dev/null || true"
    fi
done

#   cleanup
if [ ".$eval" = .0 ]; then
    rm -f $tmpfile >/dev/null 2>&1 || true
fi

