#!@l_prefix@/lib/openpkg/bash
##
##  uuid -- OpenPKG UUID Update Utility
##  Copyright (c) 2000-2007 OpenPKG Foundation e.V. <http://openpkg.net/>
##  Copyright (c) 2000-2007 Ralf S. Engelschall <http://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.
##

#   configuration
prefix="@l_prefix@"
musr="@l_musr@"
mgrp="@l_mgrp@"
prog_rpm="$prefix/libexec/openpkg/rpm"
prog_shtool="$prefix/lib/openpkg/shtool"
prog_miniperl="$prefix/lib/openpkg/miniperl"
prog_uuid="$prefix/lib/openpkg/uuid"
file_uuid="$prefix/etc/openpkg/uuid"

#   minimum command line parsing
opt_v=no
opt_m=no
while [ 1 ]; do
    case "$1" in
        -v | --verbose   ) opt_v=yes; shift ;;
        -m | --multicast ) opt_m=yes; shift ;;
        * ) break ;;
    esac
done

#   special "Nil UUID"
UUID_NIL="00000000-0000-0000-0000-000000000000"

#   Query Dynamic Information
do_query () {
    #   query RPM information
    query=":"
    for var in \
        l_openpkg_release \
        l_prefix \
        l_susr l_suid l_sgrp l_sgid \
        l_musr l_muid l_mgrp l_mgid \
        l_rusr l_ruid l_rgrp l_rgid \
        l_nusr l_nuid l_ngrp l_ngid; do
        query="$query; `echo $var | sed -e 's;^l_;Q_;'`=\"%{$var}\""
    done
    eval `$prog_rpm --eval "$query" 2>/dev/null`

    #   query OS information
    Q_platform=`$prog_shtool platform --type=binary 2>/dev/null |\
        sed -e 's;^\([^-][^-]*-[^.-][^.-]*\)\..*$;\1;'`
    if [ ".$Q_platform" = . ]; then
        Q_platform="unknown"
    fi
    Q_discriminator=`$prog_uuid -v1 | $prog_uuid -d -- - | awk '/node:.*global unicast/ { printf("mac:%s", $2); }'`
    if [ ".$Q_discriminator" = . ]; then
        Q_discriminator=`$prog_miniperl -e 'if (-f "/etc/openpkg") { printf("inode:%s", (stat("/etc/openpkg"))[1]); }' 2>/dev/null`
        if [ ".$Q_discriminator" = . ]; then
            Q_discriminator=`$prog_shtool echo -e 'fqdn:%h%d' 2>/dev/null`
        fi
    fi
}

#  Load Configuration
do_load () {
    #   start with reasonable defaults
    UUID_REGISTRY="$UUID_NIL"
    UUID_INSTANCE="$UUID_NIL"
    UUID_PLATFORM="$UUID_NIL"

    #   load configuration (and override defaults)
    if [ -r $file_uuid ]; then
        if [ ".$opt_v" = .yes ]; then
            echo "uuid: loading UUID configuration file ($file_uuid)"
        fi
        . $file_uuid
    fi

    #   remember whether something was changed
    changed=no
}

#  Save Configuration
do_save () {
    if [ ".$changed" = .yes ]; then
        #   save configuration
        if [ ".$opt_v" = .yes ]; then
            echo "uuid: saving UUID configuration file ($file_uuid)"
        fi
        if [ -f $file_uuid ] && [ ! -w $file_uuid ]; then
            echo "uuid:ERROR: cannot write to $file_uuid" 1>&2
            exit 1
        fi
        ( echo "UUID_REGISTRY=\"$UUID_REGISTRY\""
          echo "UUID_INSTANCE=\"$UUID_INSTANCE\""
          echo "UUID_PLATFORM=\"$UUID_PLATFORM\""
        ) >$file_uuid.new || exit $?
        n=`egrep 'UUID_(REGISTRY|INSTANCE|PLATFORM)="[0-9a-f-]*"' \
           $file_uuid.new | wc -l | awk '{ print $1; }'`
        if [ ".$n" != .3 ]; then
            echo "uuid:ERROR: failed to update $file_uuid" 1>&2
            rm -f $file_uuid.new
            exit 1
        fi
        cp $file_uuid.new $file_uuid || exit $?
        rm -f $file_uuid.new || true
        chown $musr:$mgrp $file_uuid >/dev/null 2>&1 || true
        chmod 644 $file_uuid >/dev/null 2>&1 || true

        #   remember that no more changes exist
        changed=no
    fi
}

#  Reset UUIDs
do_reset () {
    #   reset all UUIDs to the "Nil UUID"
    if [ ".$UUID_REGISTRY" != ".$UUID_NIL" ]; then
        UUID_REGISTRY="$UUID_NIL"
        changed=yes
    fi
    if [ ".$UUID_INSTANCE" != ".$UUID_NIL" ]; then
        UUID_INSTANCE="$UUID_NIL"
        changed=yes
    fi
    if [ ".$UUID_PLATFORM" != ".$UUID_NIL" ]; then
        UUID_PLATFORM="$UUID_NIL"
        changed=yes
    fi
}

#   Update UUIDs
do_update () {
    #   update registry UUID
    if [ ".$UUID_REGISTRY" = ".$UUID_NIL" -o ".$UUID_REGISTRY" = . ]; then
        opt=""
        if [ ".$opt_m" = .yes ]; then
            opt="-m"
        fi
        if [ ".$opt_v" = .yes ]; then
            echo "uuid: calculating OpenPKG Registry UUID (UUID_REGISTRY):"
            echo "uuid: << $prog_uuid -v1 $opt"
        fi
        uuid=`$prog_uuid -v1 $opt`
        if [ ".$UUID_REGISTRY" != ".$uuid" -a ".$uuid" != . ]; then
            UUID_REGISTRY="$uuid"
            if [ ".$opt_v" = .yes ]; then
                echo "uuid: >> $UUID_REGISTRY (NOT REPEATABLE)"
            fi
            changed=yes
        fi
    fi

    #   update instance UUID
    name="${Q_openpkg_release}"
    name="$name:${Q_prefix}"
    name="$name:${Q_susr}:${Q_suid}:${Q_sgrp}:${Q_sgid}"
    name="$name:${Q_musr}:${Q_muid}:${Q_mgrp}:${Q_mgid}"
    name="$name:${Q_rusr}:${Q_ruid}:${Q_rgrp}:${Q_rgid}"
    name="$name:${Q_nusr}:${Q_nuid}:${Q_ngrp}:${Q_ngid}"
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: querying OpenPKG Instance OID"
        echo "uuid: << $prog_rpm --eval '%{l_openpkg_oid_instance}'"
    fi
    OID_NS_INSTANCE="`$prog_rpm --eval '%{l_openpkg_oid_instance}'`"
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: >> $OID_NS_INSTANCE"
    fi
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: calculating OpenPKG Instance Namespace UUID"
        echo "uuid: << $prog_uuid -v3 ns:OID \"$OID_NS_INSTANCE\""
    fi
    UUID_NS_INSTANCE=`$prog_uuid -v3 ns:OID "$OID_NS_INSTANCE"`
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: >> $UUID_NS_INSTANCE"
    fi
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: calculating OpenPKG Instance UUID (UUID_INSTANCE):"
        echo "uuid: << $prog_uuid -v3 \"$UUID_NS_INSTANCE\" \"$name\""
    fi
    uuid=`$prog_uuid -v3 "$UUID_NS_INSTANCE" "$name"`
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: >> $uuid"
    fi
    if [ ".$UUID_INSTANCE" != ".$uuid" -a ".$uuid" != . ]; then
        UUID_INSTANCE="$uuid"
        changed=yes
    fi

    #   update platform UUID
    name="${Q_platform}"
    name="$name:${Q_discriminator}"
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: querying OpenPKG Platform OID"
        echo "uuid: << $prog_rpm --eval '%{l_openpkg_oid_platform}'"
    fi
    OID_NS_PLATFORM="`$prog_rpm --eval '%{l_openpkg_oid_platform}'`"
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: >> $OID_NS_PLATFORM"
    fi
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: calculating OpenPKG Platform Namespace UUID"
        echo "uuid: << $prog_uuid -v3 ns:OID \"$OID_NS_PLATFORM\""
    fi
    UUID_NS_PLATFORM=`$prog_uuid -v3 ns:OID "$OID_NS_PLATFORM"`
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: >> $UUID_NS_PLATFORM"
    fi
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: calculating OpenPKG Platform UUID (UUID_PLATFORM):"
        echo "uuid: << $prog_uuid -v3 \"$UUID_NS_PLATFORM\" \"$name\""
    fi
    uuid=`$prog_uuid -v3 "$UUID_NS_PLATFORM" "$name"`
    if [ ".$opt_v" = .yes ]; then
        echo "uuid: >> $uuid"
    fi
    if [ ".$UUID_PLATFORM" != ".$uuid" -a ".$uuid" != . ]; then
        UUID_PLATFORM="$uuid"
        changed=yes
    fi
}

#   Info about input and resulting UUIDs
do_info () {
    echo "OpenPKG Summary of Identification Information"
    echo "============================================="
    echo ""
    echo "OpenPKG Registry"
    time=""; clock=""; node=""
    eval `$prog_uuid -d "$UUID_REGISTRY" 2>/dev/null |\
          sed -e 's/^/X/' \
              -e 's/X.*time:  *\(.*\)$/time="\1";/' \
              -e 's/X.*clock:  *\(.*\)$/clock="\1";/' \
              -e 's/X.*node:  *\(.*\)$/node="\1";/' \
              -e 's/^X.*//'`
    echo "    System Time:           ${time:-unknown}"
    echo "    System Clock Sequence: ${clock:-unknown}"
    echo "    System Node Address:   ${node:-unknown}"
    echo "    UUID_REGISTRY:         $UUID_REGISTRY"
    echo ""
    echo "OpenPKG Instance"
    echo "    Release:               ${Q_openpkg_release}"
    echo "    Prefix:                ${Q_prefix}"
    echo "    Super Account:         ${Q_susr}(${Q_suid}):${Q_sgrp}(${Q_sgid})"
    echo "    Management Account:    ${Q_musr}(${Q_muid}):${Q_mgrp}(${Q_mgid})"
    echo "    Restricted Account:    ${Q_rusr}(${Q_ruid}):${Q_rgrp}(${Q_rgid})"
    echo "    Nonprivileged Account: ${Q_nusr}(${Q_nuid}):${Q_ngrp}(${Q_ngid})"
    echo "    UUID_INSTANCE:         $UUID_INSTANCE"
    echo ""
    echo "OpenPKG Platform"
    echo "    Platform Id:           $Q_platform"
    echo "    Discriminator:         $Q_discriminator"
    echo "    UUID_PLATFORM:         $UUID_PLATFORM"
    echo ""
    echo "(run \"$0 --verbose update\" to reproduce the UUID generation)"
}

#   Command Line Dispatching
cmd="$1"
shift
case "$cmd" in
    reset )
        do_load; do_reset; do_save
        ;;
    update )
        do_query; do_load; do_update; do_save
        ;;
    info )
        do_query; do_load; do_info
        ;;
    * )
        echo "uuid:ERROR: invalid command \"$cmd\"" 1>&2
        exit 1
        ;;
esac

