#!/bin/sh
##
##  obmtool -- OpenPKG poor man's Boot, Build & Management Tool
##  based on Ralf S. Engelschall's "devtool -- Development Tool"
##  Copyright (c) 2003 Thomas Lotterer <thomas@lotterer.net>
##   Id: obmtool,v 1.47 2005/11/30 21:19:58 thl cvs.ZfOS.org
##  $Id: obmtool,v 1.47 2005/11/30 21:19:58 thl Exp $
##

#   default parameters
prg="$0"
silent=0; verbose=0; debug=0; help=0
query=0; force=0
conf=""; logs=""; tmpdir=""; mirror=""; dltools=""; username=""; password=""
tmpfile=""; cmd=""; cmdargs=""

#   iterate over argument line
while [ $# -gt 0 ]; do
    opt="$1"
    arg=""
    arg=`echo "${opt}" | sed -e 's;^[^=]*=*;;'`
    num=`echo "${arg}" | sed -e 's;^ *\([0-9]*\).*$;\1;'`
    opt=`echo "${opt}" | sed -e 's;=.*$;;'`
    [ ".${debug}" = .1 ] && echo "DEBUG: main: opt=$opt, arg=$arg, num=$num"
    [ ".${num}" = . ] && num=1
    case $opt in
        -s|--silent    )  silent=${num} ;;
        -v|--verbose   )  verbose=${num} ;;
        -D|--debug     )  debug=${num} ;;
        -h|--help      )  help="USAGE" ;;
        -q|--query     )  query=${num} ;;
        -f|--force     )  force=${num} ;;
        -c|--conf      )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  conf="$1"
                              fi
                          else
                              conf="${arg}"
                          fi ;;
        -l|--logs      )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  logs="$1"
                              fi
                          else
                              logs="${arg}"
                          fi ;;
        -t|--tmpdir    )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  tmpdir="$1"
                              fi
                          else
                              tmpdir="${arg}"
                          fi ;;
        -m|--mirror    )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  mirror="$1"
                              fi
                          else
                              mirror="${arg}"
                          fi ;;
        -d|--dltools   )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  dltools="$1"
                              fi
                          else
                              dltools="${arg}"
                          fi ;;
        -u|--user      )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  username="$1"
                              fi
                          else
                              username="${arg}"
                          fi ;;
        -p|--pass      )  if [ ".${arg}" = . ]; then
                              if [ ".$2" != . ]; then
                                  shift 2>/dev/null
                                  password="$1"
                              fi
                          else
                              password="${arg}"
                          fi ;;
        -*             )  help="ERROR" ;;
        *              )  break;
    esac
    shift
done
cmd="$1"
if [ ".$1" = . ]; then
    help="ERROR"
else
    shift
fi
cmdargs="$@"

#   display error or usage message
if [ ".$help" != .0 ]; then
    echo "obmtool:$help: obmtool [-s|--silent] [-v|--verbose] [-D|--debug] [-h|--help]" 1>&2
    echo "                       [-q|--query] [-f|--force]" 1>&2
    echo "                       [-c|--conf <file>] [-l|--logs <dir>] [-t|--tmpdir <dir>]" 1>&2
    echo "                       [-m|--mirror <url>] [-d|dltools <tool>[:<tool>...]] [-u|--user <user>] [-p|--pass <pass>]" 1>&2
    echo "                       <cmd> [<arg> ...]" 1>&2
    if [ ".$help" = "USAGE" ]; then
        exit 0
    else
        exit 1
    fi
fi

#   compute reasonable defaults for omitted optional arguments
[ ".${conf}" = . ] && conf="`echo ${prg} | sed -e 's;^.*/;./;'`.conf"
[ ".$tmpdir" = . ] && tmpdir="${TMPDIR:-/tmp}"

#   compute scratch file name
tmpfile="$tmpdir/obmtool.$$.tmp"

#   dump debug data
if [ ".${debug}" = .1 ]; then
    echo "DEBUG: main: prg=\"$prg\"";
    echo "DEBUG: main: silent=\"$silent\" verbose=\"$verbose\" debug=\"$debug\" help=\"$help\"";
    echo "DEBUG: main: query=\"$query\" force=\"$force\"";
    echo "DEBUG: main: conf=\"$conf\" logs=\"$logs\" tmpdir=\"$tmpdir\" mirror=\"$mirror\" dltools=\"$dltools\" username=\"$username\" password=\"$password\"";
    echo "DEBUG: main: cmd=\"$cmd\" cmdargs=\"$cmdargs\"";
fi

#   check whether configuration file is readable
if [ ! -r ${conf} ]; then
    echo "obmtool:ERROR: configuration file ${conf} not readable" 1>&2
    exit 1
fi

#   check whether command in configuration file exists
cmdline=`grep "^%${cmd}$" ${conf}`
if [ ".$cmdline" = . ]; then
    echo "obmtool:ERROR: command ${cmd} not found in configuration file ${conf}" 1>&2
    exit 1
fi

#   check whether tmpdir exists
if [ ! -d "$tmpdir" ]; then
    echo "obmtool:ERROR: tmpdir \"$tmpdir\" does not exist" 1>&2
    exit 1
fi

#   create script using name $tmpfile, pass through critical variables by exporting them and run script
rm -f $tmpfile 2>&1 1>/dev/null || true
(
    sed <"${prg}" -e '1,/^##  obmtool.func {/d' -e '/^##  } obmtool.func/,$d';
    echo "    @prolog";
    sed <"${conf}" -e "1,/^%common/d" -e '/^%.*/,$d';
    echo "    @epilog";
    sed <"${conf}" -e "1,/^%${cmd} *$/d" -e '/^%.*/,$d'
) \
| sed -e 's;^\([ 	]*\)@\([a-z].*\)$;\1obmtool_\2;' >$tmpfile
export prg
export silent verbose debug help
export query force
export conf logs tmpdir
export tmpfile cmd cmdargs
export mirror dltools username password
sh $tmpfile
rc=$?
[ $rc -eq 0 ] && rm -f $tmpfile
exit $rc

##  obmtool.func { # is now embedded. This line used as cutting point. Do not remove.

##
##  obmtool.func -- OpenPKG poor man's Boot, Build & Management Tool Functions
##  based on Ralf S. Engelschall's "obmtool.func -- Development Tool Functions"
##  Copyright (c) 2003 Thomas Lotterer <thomas@lotterer.net>
##

@mkdirp ()
{
    (
        p=`echo "$1" | sed -e 's;^/;;'`
        IFS="/"
        d="/"
        for i in $p; do
            d="$d$i"
            [ -d "$d" ] || mkdir "$d" || exit 1
            d="$d/"
        done
        exit 0
    )
    return $?
}

#   find a tool; works like which(1) but vendor neutral and sets TOOL variable
@findtool ()
{
    TOOL=""
    for _tool in $*; do
        _ifs="$IFS"; IFS=":"
        for _path in $PATH; do
            if [ -f "$_path/$_tool" ]; then
                TOOL="$_path/$_tool"
                break
            fi
        done
        IFS="$_ifs"; unset _ifs
        if [ ".$TOOL" != . ]; then
            break
        fi
    done
}

@rpm ()
{
    if [ -x ${PREFIX}/bin/rpm -a ! -x ${PREFIX}/libexec/openpkg/rpm ]; then
        MPX=""
        RPM="${PREFIX}/bin/rpm"
    elif [ -x ${PREFIX}/bin/openpkg -a -x ${PREFIX}/libexec/openpkg/rpm ]; then
        MPX="${PREFIX}/bin/openpkg"
        RPM="rpm"
    else
        MPX=""
        RPM=""
    fi
}

#locate package
#   supports CURRENT and STABLE trunk - autodetected by release id
#   supports RELEASE and SOLID updates - autodetected by release id
#   supports PLUS packages - prefix with '+'
#   supports packages in CWD - prefix with './'
#   supports packages with absolute pathes - prefix with '/'
#   supports private repository - prefix with '=' and set URL
#
@locate ()
{
    LOC="."
    PKG="$1"
    ADD=""

    shift
    @archostag "$@"

    download="${mirror:-${MIRROR:-ftp://ftp.openpkg.org}}"

    # packages in CWD
    echo "${PKG}" | ${EGREP} >/dev/null '^\.\/'
    if [ $? -eq 0 ]; then
        PKG=`echo "${PKG}" | sed 's/^\.\///'` # strip off leading "./", take relative path verbatim
        return
    fi

    # packages with absolute pathes
    echo "${PKG}" | ${EGREP} >/dev/null '^\/'
    if [ $? -eq 0 ]; then
        PKG=`echo "${PKG}" | sed 's/^\/.*\///'`        # strip off leading path
        LOC=`echo "${PKG}" | sed 's/\/[^\/][^\/]*$//'` # strip off trailing file/pkg
        return
    fi

    # private repository
    echo "${PKG}" | ${EGREP} >/dev/null '^='
    if [ $? -eq 0 ]; then
        PKG=`echo "${PKG}" | sed 's/^=//'` # strip off leading "=", add URL to private repository
        LOC="$URL"
        return
    fi

    # prepare for PLUS packages
    echo "${PKG}" | ${EGREP} >/dev/null '^\+'
    if [ $? -eq 0 ]; then
        ADD="/PLUS"
        PKG=`echo "${PKG}" | sed 's/^\+//'` # strip off leading "+"
    fi

    # CURRENT
    echo ${PKG} | ${EGREP} >/dev/null -- '-[2-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$'
    if [ $? -eq 0 ]; then
        LOC="$download/current/SRC"
        return
    fi

    # STABLE
    echo ${PKG} | ${EGREP} >/dev/null -- '-[0-9][0-9]*\.[2-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$'
    if [ $? -eq 0 ]; then
        LOC="$download/stable/SRC"
        return
    fi

    # RELEASE (including PLUS)
    echo ${PKG} | ${EGREP} >/dev/null -- '-[1-9][0-9]*\.[0-9][0-9]*\.0$'
    if [ $? -eq 0 ]; then
        LOC="`echo ${PKG} | sed -e 's;^.*-\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.[0-9][0-9]*$;'$download'/release/\1.\2/SRC;'`$ADD"
        return
    fi

    # UPDATE (for CORE and BASE)
    echo ${PKG} | ${EGREP} >/dev/null -- '-[1-9][0-9]*\.[0-9][0-9]*\.[1-9][0-9]*$'
    if [ $? -eq 0 ]; then
        LOC="`echo ${PKG} | sed -e 's;^.*-\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.[0-9][0-9]*$;'$download'/release/\1.\2/UPD;'`"
        return
    fi

    echo "obmtool:ERROR: locate() does not understand how to handle \"${PKG}\"" 1>&2
    exit 1
}

#wipe out existing binary rpm
@wiperpm ()
{
    @locate "$@"
    echo "wiperpm ${PKG}"
    if [ ".$CHECKONLY" != ".yes" ]; then
        if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
            rm -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>/dev/null || true
        fi
    fi
}

#rebuild only, no install
@rebuild ()
{
    @locate "$@"
    shift
    #   FIXME compensate architectural bug of obmtool 1.3[12] placing .src.rpm files into RPM/SRC
    if [ -f ${PREFIX}/RPM/SRC/${PKG}.src.rpm ]; then
        if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
            mv ${PREFIX}/RPM/SRC/${PKG}.src.rpm ${PREFIX}/RPM/PKG/${PKG}.src.rpm 2>/dev/null || true
        fi
        rm -f ${PREFIX}/RPM/SRC/${PKG}.src.rpm 2>/dev/null || true
    fi
    if [ ".$CHECKONLY" != ".yes" ]; then
        @sanity
        @rpm
        if [ ".${TERM}" = .xterm ]; then
            echo "]0;`uname -n | sed -e 's;\..*$;;'` rebuild ${PKG} [`date '+%Y-%m-%d %H:%M:%S'`]rebuild ${PKG}"
        else
            echo "rebuild ${PKG}"
        fi
        #   download binary RPM only from local location
        if [ ".${MPX}${RPM}" != . -a ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm -a ".${LOC}" = ..  ]; then
            @fetch ${LOC}/${PKG}.${ARCH}-${OS}-${TAG}.rpm ${PREFIX}/RPM/PKG/
            if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
                ${MPX} ${RPM} --checksig ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm | egrep ' md5 ' >/dev/null
                if [ $? -ne 0 ]; then
                    echo "obmtool:WARNING: removing damaged file ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm (md5)" 1>&2
                    rm -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>/dev/null || true
                fi
            fi
        fi
        #   download source RPM only if binary RPM is missing, too
        if [ ".${MPX}${RPM}" != . -a ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm -a ! -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
            for retrygaps in 1 4 16; do
                @fetch ${LOC}/${PKG}.src.rpm ${PREFIX}/RPM/PKG/
                if [ -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
                    ${MPX} ${RPM} --checksig ${PREFIX}/RPM/PKG/${PKG}.src.rpm | egrep ' md5 ' >/dev/null
                    if [ $? -ne 0 ]; then
                        echo "obmtool:WARNING: removing damaged file ${PREFIX}/RPM/PKG/${PKG}.src.rpm (md5)" 1>&2
                        rm -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm 2>/dev/null || true
                    fi
                fi
                if [ -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
                    break
                fi
                sleep $retrygaps
            done
        fi
        #   build binary from source
        if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm -a ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
            BUILDUSER=`${MPX} ${RPM} --eval '%{?l_musr:%{l_musr}}'`
            BUILDEXEC="${MPX} ${RPM} --rebuild $@ ${PREFIX}/RPM/PKG/${PKG}.src.rpm 2>&1"
            BUILDEXEC=`echo ${BUILDEXEC} | sed \
                       -e 's;--\(define\)  *\([^=][^=]*\)=\([^ ][^ ]*\);--\\1 \\"\2 \3\\";g' \
                       -e 's;--\(use_[^=][^=]*\)=\([^ ][^ ]*\);--define \\"\1 \2\\";g' \
                       -e 's;--\(with\)=;--\1 ;g' \
                       -e 's;--\(without\)=;--\1 ;g' \
                       -e 's;--\(tag\)=;--\1 ;g' \
                       `
            [ ".${debug}" = .1 ] && echo "DEBUG: rebuild: BUILDEXEC=${BUILDEXEC}"
            if [ ".${BUILDUSER}" = . ]; then
                ( "${BUILDEXEC}" ) | tee /tmp/${PRG}-${PKG}.rebuild.log
            else
                su "${BUILDUSER}" -c "${BUILDEXEC}" | tee /tmp/${PRG}-${PKG}.rebuild.log
            fi
            if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
                    echo "obmtool:WARNING: rebuild failure. Missing ${PREFIX}/RPM/PKG/${PKG}.src.rpm" 1>&2
            fi
            echo "rebuild ${PKG} $?" >>/tmp/${PRG}.log
        fi
        if [ ".${TERM}" = .xterm ]; then
            echo "]0;`uname -n | sed -e 's;\..*$;;'`:$0"
        fi
    fi
}

#force rebuild
@forcere ()
{
    @wiperpm "$@"
    @rebuild "$@"
}

#install, rebuilds if necessary, forcibly overwrite existing
@forcein ()
{
    @locate "$@"
    TRACK="${TRACK} ${PKG}"
    if [ ".$CHECKONLY" != ".yes" ]; then
        @sanity
        echo "forcein ${PKG}"
        if [ ".${MPX}${RPM}" = . ]; then
            echo "obmtool:ERROR: rpm multiplexer/binary missing" 1>&2
            exit 1
        fi
        if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
            ${MPX} ${RPM} --checksig ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm | egrep ' md5 ' >/dev/null
            if [ $? -ne 0 ]; then
                echo "obmtool:WARNING: removing damaged file ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm (md5)" 1>&2
                rm -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>/dev/null || true
            fi
        fi
        @rebuild "$@"
        if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
            ${MPX} ${RPM} -Uvh --oldpackage --nodeps --force ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>&1 | tee /tmp/${PRG}-${PKG}.forcein.log
        else
            echo "obmtool:WARNING: forcein failure. Missing ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm" 1>&2
        fi
        echo "forcein ${PKG} $?" >>/tmp/${PRG}.log
    fi
}

#fetch a RPM (or .sh)
@fetch ()
{
    [ ".${debug}" = .1 ] && echo "DEBUG: fetch: requested that $1 is downloaded to $2"
    echo "$1 $2" | egrep '\*' >/dev/null && return 1 # short circuit for unsupported wildcards

    url=`echo "$1" | sed -e 's;^\./;file://././;'` # revamp file:// URI to look like an URL
    dst=`echo "$2" | sed -e 's;/$;;'`

    #   determine whether URL rewriting is active
    if [ ".${MPX}" != . ]; then
        rewrite=1
        echo "$url" | ${EGREP} >/dev/null '^file://' && rewrite=0
        ${MPX} register --printstatus >/dev/null 2>&1 || rewrite=0
        if [ $rewrite -eq 1 ]; then
            url=`${MPX} register --rewriteurls "$url"`
        fi
    fi

    prot=`echo $url | sed -e 's;^\([^:]*\)://\([^/]*\)/\(.*\)/\([^/]*\)$;\1;'`
    upah=`echo $url | sed -e 's;^\([^:]*\)://\([^/]*\)/\(.*\)/\([^/]*\)$;\2;'`
    dire=`echo $url | sed -e 's;^\([^:]*\)://\([^/]*\)/\(.*\)/\([^/]*\)$;\3;'`
    file=`echo $url | sed -e 's;^\([^:]*\)://\([^/]*\)/\(.*\)/\([^/]*\)$;\4;'`

    typ=1
    echo "$upah" | ${EGREP} >/dev/null '@' && typ=2
    echo "$upah" | ${EGREP} >/dev/null ':.*@' && typ=3
    case $typ in
        3) user=`echo $upah | sed -e 's;^\([^:]*\):\([^@]*\)@\(.*\)$;\1;'`
           pass=`echo $upah | sed -e 's;^\([^:]*\):\([^@]*\)@\(.*\)$;\2;'`
           host=`echo $upah | sed -e 's;^\([^:]*\):\([^@]*\)@\(.*\)$;\3;'`
           ;;
        2) user=`echo $upah | sed -e 's;^\([^@*]\)@\(.*\)$;\1;'`
           pass="${username:-${USERNAME}}_obmtool"
           host=`echo $upah | sed -e 's;^\([^@*]\)@\(.*\)$;\2;'`
           ;;
        1) user="anonymous"
           pass="${username:-${USERNAME}}_obmtool"
           host="$upah"
           ;;
    esac
    [ ".$user" = . ] && user="$username"; unoa=`echo $user | sed -e 's;@;%40;g'`
    [ ".$pass" = . ] && pass="$password"; pnoa=`echo $pass | sed -e 's;@;%40;g'`
    url="$prot://$unoa:$pnoa@$host/$dire/$file"
    [ ".${debug}" = .1 ] && echo "DEBUG: fetch: url=$url prot=$prot user=$user unoa=$unoa pass=$pass pnoa=$pnoa host=$host dire=$dire file=$file"

    [ ".${debug}" = .1 ] && echo "DEBUG: fetch: checking whether \"$dst/$file\" already present"
    [ -f "$dst/$file" ] && return 0

    if [ ".$prot" = .file ]; then
        [ ".${debug}" = .1 ] && echo "DEBUG: fetch: trying local link \"$dire/$file\" to \"$dst/$file\""
        ln "$dire/$file" "$dst/$file" 2>/dev/null
        [ $? -eq 0 -a -f "$dst/$file" ] && return 0
        [ ".${debug}" = .1 ] && echo "DEBUG: fetch: trying local copy \"$dire/$file\" to \"$dst/$file\""
        cp "$dire/$file" "$dst/$file" 2>/dev/null
        [ $? -eq 0 -a -f "$dst/$file" ] && return 0
        return 1
    else
        remainder=`echo ${dltools:-${DLTOOLS:-openpkg:curl:wget:lftp:ftp:lynx:w3m:ncftpget:ncftp}} | sed -e 's;:; ;g'`
        for tool in $remainder; do
            if [ ".$tool" = .openpkg ]; then
                TOOL="$PREFIX/lib/openpkg/curl"
            else
                @findtool $tool
            fi
            if [ -x "$TOOL" ]; then
                [ ".${debug}" = .1 ] && echo "DEBUG: fetch: trying $tool -> \"$TOOL\""
                case $tool in
                     openpkg) ( cd $dst || exit 1
                                $TOOL -o $file $url
                              ) ;;
                        curl) ( cd $dst || exit 1
                                $TOOL -o $file $url
                              ) ;;
                        wget) ( cd $dst || exit 1
                                $TOOL $url
                              ) ;;
                        lftp) ( cd $dst || exit 1
                                ( echo "cd $dire"; echo "get $file" ) | $TOOL -u $user,$pass $host
                              ) ;;
                         ftp) ( cd $dst || exit 1
                                $TOOL -? </dev/null 2>&1 | grep ftp:// >/dev/null
                                if [ $? -eq 0 ]; then
                                    $TOOL -n $url
                                else
                                    ( echo "user $user $pass"; echo "cd $dire"; echo "bin"; echo "get $file" ) | ftp -n $host
                                fi
                              ) ;;
                        lynx) ( cd $dst || exit 1
                                $TOOL --source $url >$file
                              ) ;;
                         w3m) ( cd $dst || exit 1
                                $TOOL -no-proxy -dump_source -pauth "$unoa:$pnoa" "$prot://$host/$dire/$file" >$file
                              ) ;;
                    ncftpget) ( cd $dst || exit 1
                                $TOOL $url
                              ) ;;
                       ncftp) ( cd $dst || exit 1
                                ( echo "cd $dire"; echo "bin"; echo "get $file" ) | $TOOL -u $user -p $pass $host
                              ) ;;
                esac
            fi
            [ -s "$dst/$file" ] && return 0
        done
    fi
    rm "$dst/$file"
    return 1
}

#install, rebuilds if necessary
@install ()
{
    ARGS="$@"
    @locate "$@"
    TRACK="${TRACK} ${PKG}"
    #   FIXME compensate architectural bug of obmtool 1.3[12] placing .src.rpm files into RPM/SRC
    if [ -f ${PREFIX}/RPM/SRC/${PKG}.src.sh ]; then
        if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.sh ]; then
            mv ${PREFIX}/RPM/SRC/${PKG}.src.sh ${PREFIX}/RPM/PKG/${PKG}.src.sh 2>/dev/null || true
        fi
        rm -f ${PREFIX}/RPM/SRC/${PKG}.src.sh 2>/dev/null || true
    fi
    #   FIXME compensate architectural bug of obmtool 1.3[12] placing .src.rpm files into RPM/SRC
    if [ -f ${PREFIX}/RPM/SRC/${PKG}.src.rpm ]; then
        if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
            mv ${PREFIX}/RPM/SRC/${PKG}.src.rpm ${PREFIX}/RPM/PKG/${PKG}.src.rpm 2>/dev/null || true
        fi
        rm -f ${PREFIX}/RPM/SRC/${PKG}.src.rpm 2>/dev/null || true
    fi
    if [ ".$CHECKONLY" != ".yes" ]; then
        @sanity
        #check for special package "openpkg", detect new or broken hierarchy and bootstrap
        echo "${PKG}" | ${EGREP} >/dev/null '^openpkg-[^-]+-[^-]+$'
        if [ $? -eq 0 ]; then
            [ ".${debug}" = .1 ] && echo "DEBUG: checking whether instance below ${PREFIX} is bootstrapped"
            @rpm
            if [ ".${MPX}${RPM}" = . ]; then
                echo "obmtool:NOTICE: did not find openpkg/rpm executable. Checking/fetching binary sh."
                @fetch ${LOC}/${PKG}.${ARCH:-*}-${OS:-*}-${TAG:-*}.sh ${PREFIX}/RPM/PKG/
                @fetch ${LOC}/${PKG}.${ARCH:-*}-${OS:-*}-${TAG:-*}.rpm ${PREFIX}/RPM/PKG/ #just to be complete
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH:-*}-${OS:-*}-${TAG:-*}.sh ]; then
                    echo "obmtool:NOTICE: did not find binary sh. Checking/fetching source sh."
                    @fetch ${LOC}/${PKG}.src.sh ${PREFIX}/RPM/PKG/
                    @fetch ${LOC}/${PKG}.src.rpm ${PREFIX}/RPM/PKG/ #just to be complete
                    if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.sh ]; then
                        echo "obmtool:ERROR: please download ${LOC}/${PKG}.src.sh to ${PREFIX}/RPM/PKG/ manually and restart ${PRG}" 1>&2
                        exit 1
                    fi
                    shift
                    rm -f ${PREFIX}/RPM/TMP/${PKG}.src.sh 2>/dev/null || true
                    if [ ! -f ${PREFIX}/RPM/TMP/${PKG}.src.sh ]; then
                        ln ${PREFIX}/RPM/PKG/${PKG}.src.sh ${PREFIX}/RPM/TMP/${PKG}.src.sh 2>/dev/null || true
                    fi
                    if [ ! -f ${PREFIX}/RPM/TMP/${PKG}.src.sh ]; then
                        cp ${PREFIX}/RPM/PKG/${PKG}.src.sh ${PREFIX}/RPM/TMP/${PKG}.src.sh 2>/dev/null || true
                    fi
                    if [ ! -f ${PREFIX}/RPM/TMP/${PKG}.src.sh ]; then
                        echo "obmtool:ERROR: cannot create ${PREFIX}/RPM/TMP/${PKG}.src.sh" 1>&2
                        exit 1
                    fi
                    ( cd ${PREFIX}/RPM/TMP && TMPDIR=${PREFIX}/RPM/TMP sh ${PKG}.src.sh $@ 2>&1 | tee /tmp/${PRG}-${PKG}.rebuild.log )
                    if [ $? -ne 0 ]; then
                        echo "obmtool:ERROR: building bootstrap from source using \"${PREFIX}/RPM/TMP/${PKG}.src.sh\" failed" 1>&2
                        exit 1
                    fi
                fi
                ALL=`( cd ${PREFIX}/RPM/PKG && echo ${PKG}.${ARCH:-*}-${OS:-*}-${TAG:-*}.sh )`
                for i in $ALL; do
                    if [ ".`
                    ${EGREP} <${PREFIX}/RPM/PKG/$i . \
                    | sed -e '/parse command line options/,$d' \
                    | egrep -v '^ *#' \
                    | egrep '^(p|prefix|l_prefix)=' \
                    | sed -e 's;^[^=]*=.;;' -e 's;.$;;'`" = ".${PREFIX}" ]; then
                        ( cd /tmp && sh ${PREFIX}/RPM/PKG/${i} 2>&1 | tee /tmp/${PRG}-${PKG}.install.log )
                        if [ $? -ne 0 ]; then
                            echo "obmtool:WARNING: installing bootstrap from binary \"${PREFIX}/RPM/PKG/${i}\" failed" 1>&2
                        fi
                        break;
                    fi
                done
                @rpm
                if [ ".${MPX}${RPM}" = . ]; then
                    echo "obmtool:ERROR: bootstrapping failed" 1>&2
                    exit 1
                fi
            else
                if [ ".${TAGFMT}" = . ]; then
                    ARGS="$1"
                else
                    ARGS="$1 --tag=${TAGFMT}"
                fi
            fi
        fi
        echo "install ${PKG}"
        @rpm
        if [ ".${MPX}${RPM}" = . ]; then
            echo "obmtool:ERROR: rpm multiplexer/binary missing" 1>&2
            exit 1
        fi
        if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
            ${MPX} ${RPM} --checksig ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm | egrep ' md5 ' >/dev/null
            if [ $? -ne 0 ]; then
                echo "obmtool:WARNING: removing damaged file ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm (md5)" 1>&2
                rm -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>/dev/null || true
            fi
        fi
        ${MPX} ${RPM} -q >/dev/null ${PKG}
        if [ $? -eq 0 ]; then
            if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
                MD5QP=`${MPX} ${RPM} -qp --qf '%{SIGMD5}' ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm`
                MD5DB=`${MPX} ${RPM} -q  --qf '%{SIGMD5}' ${PKG}`
                if [ ".$MD5QP" != ".$MD5DB" ]; then
                    echo "obmtool:WARNING: replacing installed ${PKG} with same name-version-release file having different message digest" 1>&2
                    ${MPX} ${RPM} -Uvh --force --nodeps ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>&1 | tee /tmp/${PRG}-${PKG}.install.log
                fi
            fi
        else
            @rebuild ${ARGS}
            if [ -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
                ${MPX} ${RPM} -Uvh --oldpackage --nodeps ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm 2>&1 | tee /tmp/${PRG}-${PKG}.install.log
            else
                echo "obmtool:WARNING: install failure. Missing ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm" 1>&2
            fi
            echo "install ${PKG} $?" >>/tmp/${PRG}.log
        fi
    fi
}

#trigger force rebuild, force install
@trigger ()
{
    @forcere "$@"
    @forcein "$@"
}

@prolog ()
{
    ##
    ##  obmtool has the call to the prolog() function hardcoded as the
    ##  prolog of the %common scriplet. It is placed immediately after the
    ##  obmtool.func has been read.
    ##
    #M  prolog() initializes variables which can be used throughout the scriptlets
    #M
    #M  PRG = name of the program as seen in $0 of the obm but with leading path stripped off
    #M  CMD = name of the command as seen in $1 of the obm
    #M  URL = URL to private packages
    #M  TRACK = whitespace separated list of tracked packages, preinitialized to empty string
    #M  EGREP = name of egrep(1) program
    #M  CHECKONLY = yes|no; set to yes if --query option given
    #M  ERASESURPLUS = yes|no; set to yes if --force option given
    #M  HASX11 = yes|no; set to yes if X11 client libs available (xauth probed)
    #M  PREFIX = /openpkg; default can be overridden in %common scriptlet
    #M  NODE = dv1.dev.de.cw.net; uname -n

    #   dump debug data
    if [ ".${debug}" = .1 ]; then
        echo "DEBUG: prolog: prg=\"$prg\"";
        echo "DEBUG: prolog: silent=\"$silent\" verbose=\"$verbose\" debug=\"$debug\" help=\"$help\"";
        echo "DEBUG: prolog: query=\"$query\" force=\"$force\"";
        echo "DEBUG: prolog: conf=\"$conf\" logs=\"$logs\" tmpdir=\"$tmpdir\"";
        echo "DEBUG: prolog: cmd=\"$cmd\" cmdargs=\"$cmdargs\"";
    fi

    PRG="`echo ${prg} | sed -e 's/.*\///'`"
    CMD="${cmd}"

    URL=""
    TRACK=""

    if [ -x /usr/xpg4/bin/egrep ]; then
        EGREP=/usr/xpg4/bin/egrep
    else
        EGREP=egrep
    fi

    if [ -d /usr/ccs/bin ]; then
        PATH=/usr/ccs/bin:${PATH}
        export PATH
    fi

    CHECKONLY="no"
    if [ ".${query}" = .1 ]; then
        CHECKONLY="yes"
    fi

    ERASESURPLUS="no"
    if [ ".${force}" = .1 ]; then
        ERASESURPLUS="yes"
    fi

    HASX11=""
    if [ -x /usr/X11R6/bin/xauth -o -x /usr/openwin/bin/xauth -o -x /usr/bin/X11/xauth ]; then
    #   search for include and Intrinsic.h taken from x11-1.3.1-1.3.1
    #   search for include directory
    for incdir in \
        /usr/openwin/include \
        /usr/openwin/share/include \
        /usr/[xX]/include \
        /usr/[xX]11*/include \
        /usr/[xX]386/include \
        /usr/[xX]ree86/include \
        /usr/include \
        /usr/include/[xX] \
        /usr/include/[xX]11* \
        /usr/include/[xX]386 \
        /usr/include/[xX]free86 \
        /usr/local/include \
        /usr/local/include/[xX] \
        /usr/local/include/[xX]11* \
        /usr/local/include/[xX]386 \
        /usr/local/include/[xX]free86 \
        /usr/local/[xX]/include \
        /usr/local/[xX]11*/include \
        /usr/local/[xX]386/include \
        /usr/local/[xX]ree86/include \
        /usr/athena/include \
        /usr/unsupported/include \
    ; do
        if [ -f "$incdir/X11/Intrinsic.h" ]; then
            x11_incdir="$incdir"
            HASX11="yes"
            break
        fi
    done
    fi

    # remove double slashes and trailing slashes
    PREFIX=`echo "${PREFIX}" | sed -e 's;//*;/;g' -e 's;/$;;'`

    NODE="`uname -n`"

    @archostag
    echo "${PRG}:${CMD}:NOTICE: restart `date '+%Y-%m-%d %H:%M:%S'`" >>/tmp/${PRG}.log
}

@epilog ()
{
    ##
    ##  obmtool has the call to the epilog() function hardcoded as the
    ##  epilog of the %common scriplet. It is placed immediately after the
    ##  %common scriptlet.
    ##
    #M  epilog() initializes variables which can be used throughout the scriptlets

    #   dump debug data
    if [ ".${debug}" = .1 ]; then
        echo "DEBUG: epilog: prg=\"$prg\"";
        echo "DEBUG: epilog: silent=\"$silent\" verbose=\"$verbose\" debug=\"$debug\" help=\"$help\"";
        echo "DEBUG: epilog: query=\"$query\" force=\"$force\"";
        echo "DEBUG: epilog: conf=\"$conf\" logs=\"$logs\" tmpdir=\"$tmpdir\"";
        echo "DEBUG: epilog: cmd=\"$cmd\" cmdargs=\"$cmdargs\"";
    fi

    @archostag

    # check whether a obsolete obmtool.conf tries to use us
    error=0
    for var in CWUSER CWGROUP TARGET_PATH TAGFMT CWMUID CWRUID CWNUID CWMGID CWRGID CWNGID; do
        val=`eval "echo \\$${var}"`
        if [ ".${val}" != . ]; then
            echo "obmtool:WARNING: obsolete variable ${var} set to \"${val}\"" 1>&2
            error=1
        fi
    done
    if [ ${error} -ne 0 ]; then
        echo "obmtool:ERROR: variables used which are no longer supported by obmtool" 1>&2
        exit 1
    fi

}

@hasfeature ()
{
    missing=""
    for feature in "$@"; do
        case $feature in
            TAGFMT)   ;;
            USE)      ;;
            DEFINE)   ;;
            MIRROR)   ;;
            DLTOOLS)  ;;
            REGISTRY) ;;
                 *) missing="$missing $feature";;
        esac
    done
    if [ ".$missing" != . ]; then
        echo "obmtool:WARNING: ${file} requires \"$missing\" feature(s) which this obmtool does not provide" 1>&2
        return 1
    fi
    return 0
}

@locationid ()
{
    echo "obmtool:ERROR: ${file} calls locationid which is deprecated by archostag()" 1>&2
    exit 1
}

@tagfmtfromargs ()
{
    TAGFMT=""
    for i in "$@"; do
        case $i in
            --tag=*) TAGFMT=`echo $i | sed -e 's;^--tag=;;'` ;;
        esac
    done
}

@archostag ()
{
    #M archostag() initializes variables which can be used throughout the scriptlets
    #M             they are queried from a rpm installed below PREFIX, if available.
    #M             Otherwise they are set to an empty string.
    #M
    #M   TAG = cw; locationid (OpenPKG v1.x) or tag (OpenPKG v2.x)
    #M  ARCH = ix86; architecture
    #M    OS = freebsd4.8; operating system

    @tagfmtfromargs "$@"
    @rpm
    if [ ".${MPX}${RPM}" != . ]; then
        ARCH=`${MPX} ${RPM} -q --qf "%{ARCH}" openpkg`
        OS=`${MPX} ${RPM} --eval "%{?l_host_os:%{l_host_os}}"`
        if [ ".${OS}" = . ]; then
            OS=`${MPX} ${RPM} -q --qf "%{OS}" openpkg`
        fi
        if [ ".${TAGFMT}" = . ]; then
            TAG=`${MPX} ${RPM} --eval '%{?l_tag:%{l_tag}}%{!?l_tag:%{l_location}}'`
        else
            TAG=`${MPX} ${RPM} --define "l_tag_fmt ${TAGFMT}" --eval '%{?l_tag:%{l_tag}}%{!?l_tag:%{l_location}}'`
        fi
    else
        ARCH=""
        OS=""
        TAG=""
    fi

}

@sanity ()
{
    #   sanity check
    if [ ".$PREFIX" = . ]; then
        echo "obmtool:ERROR: sanity check asserted PREFIX is set but it is empty" 1>&2
        exit 1
    fi

    #   check whether SRC|PKG|TMP either exist or can be created and are writable
    error=0
    for s in SRC PKG TMP; do
        d="$PREFIX/RPM/$s"
        @mkdirp "$d"
        if [ ! -d "$d" ]; then
            echo "obmtool:WARNING: directory \"$d\" does not exist after attempt to create it"
            error=1
        fi
        touch "$d/.writetest" 2>/dev/null
        if [ $? -ne 0 ]; then
            echo "obmtool:WARNING: directory \"$d\" not writable"
            error=1
        fi
        rm "$d/.writetest"
    done
    if [ ${error} -ne 0 ]; then
        echo "obmtool:ERROR: directory structure below prefix \"$PREFIX\" not accessible" 1>&2
        exit 1
    fi
}

@status ()
{
    ${PREFIX}/etc/rc all status | grep active
}

@check ()
{
    INSTALL=""
    MISSSRC=""
    MISSPKG=""
    MISSING=""
    SURPLUS=""
    @rpm
    if [ ".${MPX}${RPM}" = . ]; then
        MISSING="${TRACK}"
    else
        ALL=`${MPX} ${RPM} -qa`
        for PKG in ${TRACK}
        do
            ${MPX} ${RPM} -q ${PKG} 2>&1 >/dev/null
            if [ $? -eq 0 ]; then
                INSTALL="${INSTALL} ${PKG}"
                ALL=`echo "${ALL}" | ${EGREP} -v "^${PKG}"`
            else
                MISSING="${MISSING} ${PKG}"
            fi
            echo "${PKG}" | ${EGREP} >/dev/null '^openpkg-[^-]+-[^-]+$'
            if [ $? -eq 0 ]; then
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.sh ]; then
                    MISSPKG="${MISSPKG} ${PKG}.${ARCH}-${OS}-${TAG}.sh"
                fi
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
                    MISSPKG="${MISSPKG} ${PKG}.${ARCH}-${OS}-${TAG}.rpm"
                fi
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.sh ]; then
                    MISSSRC="${MISSSRC} ${PKG}.src.sh"
                fi
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
                    MISSSRC="${MISSSRC} ${PKG}.src.rpm"
                fi
            else
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.${ARCH}-${OS}-${TAG}.rpm ]; then
                    MISSPKG="${MISSPKG} ${PKG}"
                fi
                if [ ! -f ${PREFIX}/RPM/PKG/${PKG}.src.rpm ]; then
                    MISSSRC="${MISSSRC} ${PKG}"
                fi
            fi
        done
    fi
    if [ ! -d ${PREFIX}/RPM/PKG ]; then
        MISSPKG="all, ${PREFIX}/RPM/PKG empty"
        MISSSRC="all, ${PREFIX}/RPM/PKG empty"
    fi

    if [ ".${ALL}" != "." ]; then
        for i in ${ALL}
        do
            echo "$i" | ${EGREP} "^gpg-pubkey-" 2>&1 >/dev/null || SURPLUS="${SURPLUS}${SURPLUS:+ }$i"
        done
        if [ ".${ERASESURPLUS}" = ".yes" ]; then
            echo "ERASING: ${SURPLUS:-none}"
            if [ ".${SURPLUS}" != . ]; then
                ${MPX} ${RPM} -e ${SURPLUS} --allmatches 2>&1 >/dev/null
            fi
        fi
    fi

    SUMMARY=""
    DATE="`date '+%Y-%m-%d/%H:%M:%S'`"
    if [ ".${TERM}" = .xterm ]; then
        SUMMARY="${SUMMARY}]0;NODE=${NODE}; DATE=${DATE}; DONE"
    fi
    SUMMARY="${SUMMARY}NODE=${NODE}; CMD=${CMD}; DATE=${DATE}; HASX11=${HASX11}; DONE"

    INSTALL="`echo ${INSTALL}`"
    MISSSRC="`echo ${MISSSRC}`"
    MISSPKG="`echo ${MISSPKG}`"
    MISSING="`echo ${MISSING}`"
    SURPLUS="`echo ${SURPLUS}`"

    echo "INSTALL: ${INSTALL:-none}"
    echo "MISSSRC: ${MISSSRC:-none}"
    echo "MISSPKG: ${MISSPKG:-none}"
    echo "MISSING: ${MISSING:-none}"
    echo "SURPLUS: ${SURPLUS:-none}"
    echo "SUMMARY: ${SUMMARY:-none}"
}
##  } obmtool.func # is now embedded. This line used as cutting point. Do not remove.

