#!/bin/sh
#
# $Id: script-header,v 1.82.4.1 2006/10/09 20:42:23 sjg Exp $
#
# Copyright (c) 1999-2006, Juniper Networks, Inc.
# All rights reserved.
#
# Package requirement review and installation script (base form)
#
# This script is run after the tar file has been unpacked into the /var
# sandbox area but before anything has actually been moved to the final
# location upon installation, and also once again upon deinstallation.
#
# When it is called for installation via REQUIRE, it's called with
# the second argument set to "INSTALL", upon deinstallation "DEINSTALL".
# When it's called for installation via INSTALL, it's called with
# "PRE-INSTALL" and "POST-INSTALL". We leave it to the derived script
# to deal with these conditions; we just record them in $instance.
#
# The model is that each package's REQUIRE script defines a set of
# variables that represent the facilities (and internal version
# number of those facilities) offered or required by that package.
# The functions in this file get those variables and compare them
# to see if the services required match those offered. Other scripts
# allow the user to check whether a set of packages will work together
# or if a reboot is (or will be) required after upgrade.
# 
# $PKG_* variables are set by the "package" script
#

#
# If we're only after variable-setup, we don't want _anything_
# out of this file. The closing 'fi' for the following 'if' is
# the last thing in this file. Think of this as '#ifndef foo/#define foo'
# lines from a C header file....
#
if [ -z "$PKG_SETUP_VARIABLES_ONLY" ]; then
# The closing 'fi' is at the bottom of the file.

pkg_LCK=/tmp/.pkg.LCK
pkg_db_dir=/etc/db/pkg
pkg_tag=
fail=0

# cookie to allow us to keep user under control...
junos_reboot_pending=/var/run/pkg-reboot-pending

# UI variable settings
mgd=/usr/sbin/mgd
mgd_last=$mgd.last
config_database=/var/run/db/juniper.db
# handle compressed configs
for config_file in /config/juniper.conf.gz /config/juniper.conf
do
    [ -f $config_file ] && break
done
config_changes=/var/db/config/juniper.conf.pre-install

jkernel_require=/var/run/jkernel.require

jkernel_require_is_not_old() {
    local uname cur
    uname=`uname -v | awk '{print $2}'`
    cur=`awk -F= '/^current_release/ { print $2 }' < $jkernel_require`
    [ "$uname" = "$cur" ]
}

#
# dot_jkernel_require
#
# At boot time, the currently installed jkernel's +REQUIRE
# script's variables are tucked into /var/run/jkernel.require
# so we can know information about the running kernel.
dot_jkernel_require() {
    if [ -r $jkernel_require ]; then
	if jkernel_require_is_not_old ; then
	    trace Sourcing jkernel.require ...
	    . $jkernel_require
	fi
    fi
}

# dot_run_require
#
# Generic form of dot_jkernel_require
# Currently used for jbase.
dot_run_require() {
    local run_require

    run_require=/var/run/$1.require
    if [ -r $run_require ]; then
        trace Sourcing $1.require ...
	. $run_require
    fi
}


# rm_symlinks <package-name>
#
# If the file $pkgdir/$package.symlinks exists
# we remove the links that are not marked no_unlink
# This should only be called for non-core packages and when
# $PKG_FORCE is set.
#
rm_symlinks() {
    DebugOn rm_symlinks
    local old_symlinks

    old_symlinks=${1:-$pkgdir/$package.symlinks}

    if [ -s $old_symlinks ]; then
        while read src target flags
	do
	    case "$flags" in
	    *no_unlink*) continue;;
	    esac
	    /bin/rm -f $DESTDIR$target
	done < $old_symlinks
    fi
    DebugOff rm_symlinks
}

# compatability routines for transition...
symlink_package() {
    make_symlinks
}

rm_symlink_package() {
    case "$package" in
    jbase|jroute|jkernel|jpfe*|jdocs)
        [ "$PKG_FORCE" ] || return
        ;;
    esac
    rm_symlinks
}

# code that shouldn't be replicated in each +[DE]INSTALL
package_pre_install() {
    DebugOn package_pre_install
    run_hooks package_pre_install_hooks
    replace_package_mount

    [ -d /usr/share/help/syslog-modules ] ||
        (umask 022; /bin/mkdir -p /usr/share/help/syslog-modules)
    DebugOff package_pre_install
}

package_post_install() {
    DebugOn package_post_install
    run_hooks package_post_install_hooks
    if [ ! -s $pkgdir/$pkgfile ]; then
        # it was marked @ignore_inst
        trace installing $pkgdir/$pkgfile
        cp -p .$base_pkgdir/$pkgfile .$base_pkgdir/$pkgfile.md5 .$base_pkgdir/$pkgfile.sha1 $pkgdir
	chflags schg $pkgdir/$pkgfile $pkgdir/$pkgfile.md5 $pkgdir/$pkgfile.sha1
    fi
    make_symlinks
    if [ -s ./$package.symlinks ]; then
        # will need these later
        trace installing $pkgdir/$package.symlinks
        cp -p ./$package.symlinks $pkgdir/$package.symlinks
    fi
    if [ -z "$PKG_BOOTSTRAP" ] ; then
        # even if we plan to reboot, we need to mount the packages
        # in case the user delays rebooting and wants to install
        # something else.
        case `mount | grep "$pkgfile "` in
	"") trace mounting $pkgfile
	    /bin/sh $base_mountpkg
	    ;;
	esac
    fi
    [ -d /var/db/help ] ||
        (umask 022; /bin/mkdir -p /var/db/help )
    [ -s /usr/share/help/syslog-modules/$package.help.tgz ] &&
        /bin/rm -f /var/db/help/syslog.help.tgz
    if [ -z "$PKG_BOOTSTRAP" ]; then
	if ! need_to_reboot; then
	    # for non-core packages only...
	    if [ "$HasDaemons" ]; then
		kick_off_daemons $HasDaemons
	    else
		[ "$HasDDL" ] && restart_mgd
		[ "$HasOtherDaemons" ] && kick_off_other_daemons $HasOtherDaemons
	    fi
	fi
    fi
    DebugOff package_post_install
}

# common deinstall functionality
package_deinstall() {
    DebugOn package_deinstall
    run_hooks package_deinstall_hooks
    case "$package" in
    jbase|jroute|jkernel|jpfe*|jdocs)
        [ "$PKG_FORCE" ] || { DebugOff package_deinstall; return; }
        ;;
    esac
    /bin/rm -df $base_mountdir
    /bin/rm -f $mountpkg
    /bin/rm -f $base_mountpkg
    rm_symlink_package
    DebugOff package_deinstall
}

package_post_deinstall() {
    DebugOn package_post_deinstall
    run_hooks package_post_deinstall_hooks
    case "$package" in
    jbase|jroute|jkernel|jpfe*|jdocs)
        [ "$PKG_FORCE" ] || { DebugOff package_post_deinstall; return; }
        ;;
    esac
    case "$package" in
    jkernel)
        /bin/rm -f $base_umountpkg
        ;;
    *)
        [ -s $umountpkg ] && /bin/sh ${umountpkg} 2>/dev/null
        /bin/rm -f $base_umountpkg
        /bin/df | /usr/bin/grep -q "$mountdir"
        if [ $? = 1 ] ; then
    	    /bin/rm -f $umountpkg
	    /bin/rm -df $mountdir
        fi
        ;;
    esac
    # will still be there if marked @ignore_inst
    chflags noschg $pkgdir/$pkgfile $pkgdir/$pkgfile.md5 $pkgdir/$pkgfile.sha1 >/dev/null 2>&1
    /bin/rm -f $pkgdir/$pkgfile $pkgdir/$pkgfile.md5 $pkgdir/$pkgfile.sha1 $pkgdir/$package $pkgdir/$package.symlinks
    if [ -z "$PKG_UPGRADE" ]; then
	if ! need_to_reboot; then
	    [ "$HasDDL" ] && restart_mgd
	    [ "$HasKillDaemons" ] && daemon_kill $HasKillDaemons
	fi
    fi
    DebugOff package_post_deinstall
}


# cleanup_package <package> <ignore>
#
# this routine cleans up the previously mounted versions of
# <package>, being careful to ignore <ignore> (usually pkgfile)
# incase we are installing the same version of the package.
# 
cleanup_package() {
    DebugOn cleanup_package
    local package ignore backup needclean mounted pkg pkgpath

    package=$1
    ignore=${2:-$pkgfile}
    backup=${3:-/dev/null}
    trace cleanup_package $package $ignore

    case $package in
    jpfe) pkgmatch="jpfe-[^c]";;
    *)    pkgmatch="$package-";;
    esac
    needclean=/tmp/.cln$$
    mounted=/tmp/.cln$$.m
    > $needclean
    > $mounted
    #
    # note that this will never match jbase - that only gets
    # unmounted at reboot time
    #
    # don't include anything that's a memfs here, that's a submount
    # for a mounted package
    #
    mount | sed -n -e "/mfs:/d" -e "/mnt\/$pkgmatch/s,mnt/,mnt ,p" |
    while read vndev j1 j2 mounted_package j3
    do
	# this helps debug issues...
	: vndev=$vndev mounted_package="$mounted_package" ignore="$ignore"
	echo ${mounted_package##*/} >> $mounted
        case "$mounted_package" in
	$ignore) trace skipping $ignore
            continue
            ;;
	$backup) trace skipping $backup
            continue
            ;;
	esac
        trace cleaning up $mounted_package
        # try to unmount it
        if umount $pkgdir_mnt/$mounted_package 2>/dev/null; then
            vnconfig -u -v $vndev >/dev/null 2>&1
	    rm -f $base_pkgdir/umount.$mounted_package
	else
	    # communicating to the parent of a redirected
	    # loop can be a pain...
	    echo $package > $needclean
	fi
        if [ -s $base_pkgdir/mount.$mounted_package ]; then
            # see if it can tell us where the pkgfile is
            eval `grep pkgpath= $base_pkgdir/mount.$mounted_package; :`
        fi
        pkgpath=${pkgpath:-$pkgdir/$mounted_package}
        rm -f $base_pkgdir/mount.$mounted_package
        rm -df $pkgdir_mnt/$mounted_package 2>/dev/null
        chflags noschg $pkgpath $pkgpath.md5 $pkgpath.sha1 >/dev/null 2>&1
        rm -f $pkgpath $pkgpath.md5 $pkgpath.sha1
    done
    if [ -s $needclean ]; then
	clean_pkg_list="$clean_pkg_list $package"
    fi
    /bin/rm -f $needclean
    (cd $pkgdir
    for old_package in ${pkgmatch}*
    do
        case "$old_package" in
	$ignore|$ignore.*) trace skipping $old_package
            continue
            ;;
	$backup|$backup.*) trace skipping $backup
            continue
            ;;
	*\*) break;;		# there are none?
	esac
        trace cleaning up $old_package
        rm -df $pkgdir_mnt/$old_package 2>/dev/null
        chflags noschg $old_package $old_package.md5 $old_package.sha1 >/dev/null 2>&1
        rm -f $base_pkgdir/*mount.$old_package $old_package $old_package.md5 $old_package.sha1
    done
    # real dregs...
    cd $base_pkgdir
    for old_package in *mount.${pkgmatch}*
    do
	case "$old_package" in
	*.$ignore) trace skipping $ignore
            continue
	    ;;
	*.$backup) trace skipping $backup
            continue
            ;;
	*\*) break;;		# there are none?
	esac
	trace cleaning up $old_package
	rm -f $old_package
    done
    cd $pkgdir_mnt
    mounted=`cat $mounted; rm -f $mounted`
    for old_mnt in ${pkgmatch}*
    do
	case "$old_mnt" in
	$ignore) trace skipping $ignore
            continue
            ;;
	$backup) trace skipping $backup
            continue
            ;;
	*\*) break;;		# there are none?
	esac
	case " $mounted " in
	*" $old_mnt "*) continue;;
	esac
	trace cleaning up old mountdir $old_mnt
	rmdir $old_mnt 2>/dev/null || trace $old_mnt still busy
    done
    )
    trace cleanup_package finished.
    DebugOff cleanup_package
}

# Don't assume that pkg_delete did anything but
# remove the record of the package being installed.
# 
replace_package_mount() {
    DebugOn replace_package_mount
    trace replacing mount for $package $pkgfile

    cleanup_package $package $pkgfile

    # we don't get called for jbase, but just in case...
    if [ "$package" != jbase ]; then
        create_mount_package $pkgdir/$pkgfile $mountdir > $mountpkg
        create_umount_package $pkgdir/$pkgfile $mountdir > $umountpkg
        make_package_links
	if [ -z "$PKG_BOOTSTRAP" -a "$clean_pkg_list" -a -s /sbin/cleanup-pkgs ]; then
	    if ! need_to_reboot; then
		trace Spawning cleanup-pkgs
		/bin/sh /sbin/cleanup-pkgs >> /var/log/cleanup-pkgs 2>&1 < /dev/null &
	    fi
	fi
    fi
    DebugOff replace_package_mount
}

#
# initialize <package-name> <pass-name>
#
# Initialize the environment
#
initialize() {
    DebugOn initialize $1 $2 $1:$2
    if [ ! -z "$PKG_TRACE_SHELL" ]; then
	set -x
	set # Show current variable settings
    fi
    if [ ! -w /etc -a -d /etc/db/pkg/junos ]; then
	# some things must be skipped and others done...
	PKG_NOT_JUNOS=:
	PKG_IS_JUNOS=
    else
	PKG_NOT_JUNOS=
	PKG_IS_JUNOS=:
    fi

    trace Initializing $0 package $1 for operation $2 in `pwd`

    # Package name
    package=$1

    # instance will be INSTALL/DEINSTALL/PRE-INSTALL/POST-INSTALL
    instance=$2

    # Fix the path to a known good value
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:${PATH}
    export PATH

    # We have (probably) just extracted the entire package into
    # the current directory ($instmp)
    instmp=`pwd`

    if [ -z $PKG_BOOTSTRAP ] ; then
        dot_jkernel_require
    fi
    #
    # The various mount/umount scripts
    # Some wrinkles due to the fact that we have jpfe-*
    # which we want registered as jpfe.
    # Thus we no longer assume that pkgfile=$package-8.2R1.7.
    # base_* are the canonical locations - known to /etc/rc et al
    # the distinction between base_pkgdir and pkgdir is that for
    # packages like jdiag and jtools pkgdir may be set to
    # /var/packages so that the .iso will be kept off the flash.
    pkgfile=jweb-8.2R1.7
    base_pkgdir=/packages
    pkgdir=${pkgdir:-$base_pkgdir}
    pkgdir_mnt=$base_pkgdir/mnt
    base_mountdir=$pkgdir_mnt/$package
    base_mountpkg=$base_pkgdir/mount.$package
    base_umountpkg=$base_pkgdir/umount.$package
    finish_install=$base_pkgdir/finish-install.$package
    finish_deinstall=$base_pkgdir/finish-deinstall.$package

    mountdir=$pkgdir_mnt/$pkgfile
    mountpkg=$base_pkgdir/mount.$pkgfile
    umountpkg=$base_pkgdir/umount.$pkgfile

    if [ -z $PKG_BOOTSTRAP ] ; then
        [ -d $pkgdir ] || /bin/mkdir -p $pkgdir
    fi
    clean_pkg_list=

    # jbundle and/or package.sh set this to a file, so that
    # we can detect across packages that a reboot is needed.
    PKG_NEED_TO_REBOOT=${PKG_NEED_TO_REBOOT:-/dev/null}
    if [ -s $PKG_NEED_TO_REBOOT ]; then
        . $PKG_NEED_TO_REBOOT
    fi
    DebugOff initialize
}

#
# dire_warn <message> ...
#
# Warns with a fist
#
dire_warn() {
    local reason=
    case "$1" in
    -r) reason=$2; shift 2;;
    esac
    warn "$@"
    # we ignore -force in some cases
    case ",${PKG_NEVER_FORCE:-noforce}," in
    *,"$reason",*) warn_abort $reason;;
    esac
    # PKG_FORCEABLE is set when -force is given, even if
    # PKG_FORCE is suppressed (on some platforms).
    # Thus if our $reason is in $PKG_FORCEABLE we should not abort.
    # Otherwise we consider PKG_FORCE...
    case ",${PKG_FORCEABLE:-nothing}," in
    *,$reason,*) ;;
    *)
        if [ -z "$PKG_FORCE" ]; then
            warn_abort $reason
        fi
        ;;
    esac
}


#
# warn_abort
#
# When something is wrong, bail. When something is very wrong, bail faster.
#
warn_abort() {
    warn
    warn "This installation attempt will be aborted."
    # There are some things we never allow to be forced (on some platforms).
    # So we don't want to recommend -force for those.
    case ",${PKG_NEVER_FORCE:-noforce}," in
    *,"$1",*) ;;
    *)
        warn "If you wish to force the installation despite these warnings"
        warn "you may use the 'force' option on the command line."
        ;;
    esac
    Exit 1
}


# platform_check, a number of packages need this now...
# platform_check jseries|juniper
platform_check() {
    DebugOn platform_check

    product_model=`sysctl -n hw.product.model`
    re_model=`sysctl -n hw.re.model`
    case "$1:$product_model:$re_model" in
    *:olive) ;;			# ok
    jseries:j[1-9][0-9][0-9][0-9]:*) ;; # ok
    # Hack to get jsr image on the jseries box.
    jsr:j[1-9][0-9][0-9][0-9]:*) ;; # ok
    jseries:jsr[1-9][0-9][0-9][0-9]:*) ;; # ok
    jsr:jsr[1-9][0-9][0-9][0-9]:*) ;; # ok
    jseries:*)
	Error "Unsupported platform $product_model, use a non-jseries package"
	;;
    *:j[1-9][0-9][0-9][0-9]:*)
	Error  "Unsupported platform $product_model, use a jseries package"
	;;
    esac
    DebugOff platform_check
}

#
# version_check
#
# Check package against base OS.
#
version_check() {
    DebugOn version_check
    # PKG_MIN_JUNOS_MAJOR is set by jbundle's +INSTALL
    local major_re=${1:-$PKG_JUNOS_MAJOR_OK}

    case "$major_re" in
    \[[1-9]*) ;;
    [1-9]*)	
        if [ $major_re -lt 8 ]; then
	    major_re="[${major_re}-8]"
        else
            major_re="[8-$major_re]"
	fi
        ;;
    *)	major_re="8";;
    esac
    grep -qs "$major_re\.[0-9]" /etc/db/pkg/junos/+COMMENT
    if [ $? != 0 ] ; then
	run_hooks version_check_fail_hooks
	warn
	warn "This base version of JUNOS will not properly"
	warn "support this package.  Please install base OS"
	warn "JUNOS 8.0 or newer ASAP.  You can do this via"
	warn "a jinstall package or install-media."
	case "./$package" in
	*/jbundle*) # nothing removed yet, so no need to rollback.
	    ;;
	*)  # previous package has likely been removed so be helpful.
	    warn
	    warn "Or use the command:"
	    warn
	    warn "	'request system software rollback'"
	    warn
	    warn "to attempt to restore the previous software set."
	    ;;
	esac
	warn
	warn "This installation attempt will be aborted."
	warn
	Exit 1
    fi
    DebugOff version_check
}

#
# storage_check
#
# Check to make sure we've got enough space.
#
storage_check() {
    DebugOn storage_check
    local minfree=${1:-2048}

    if [ -z "$PKG_STORAGE_CHECK_DISABLED" ]; then
	# get space available - and where it is.
	eval `df -k /packages | ( read h; read d s u a c o; echo available=$a on=$o )`
	suggested=`du -ks $instmp | ( read one two; echo $one )`

	# make sure root always has $minfree mb to spare
	suggested=`expr $suggested + $minfree`

	inform "Available space: $available require: $suggested"

	if [ $suggested -ge $available ] ; then
	    warn
	    case ${on:-/} in
	    /junos/cf) on=/cf;;
	    /) on=root;;
	    esac
	    warn "The $on filesystem is low on free disk space."
	    warn "This package requires ${suggested}k free, but there"
	    warn "is only ${available}k available."

	    run_hooks storage_check_fail_hooks

	    warn_abort space
	fi
    else
	trace Storage check is disabled
    fi
    DebugOff storage_check
}

# return true if veriexec is being enforced
veriexec_check() {
    if [ -x /sbin/veriexec ]; then
	(/sbin/veriexec -i enforce) > /dev/null 2>&1
	return $?
    fi
    return 1
}

unpack_pkgtools() {
    if [ -s $instmp/pkgtools.tgz -a ! -s $instmp/pkg/manifest ]; then
	    (cd $instmp && tar zxf pkgtools.tgz)
	    # if veriexec is present, we probably need to use it
	    veriexec_check && /sbin/veriexec -C $instmp $instmp/pkg/manifest
    fi
}

#
# pic combination check
#
# Certain pic combinations in a pic are not allowed
#
pic_combination_check() {
    unpack_pkgtools
    $instmp/bin/checkpic || dire_warn -r pic
}

#
# dot_file <package-name> [quietly]
#
# Dot (source) a package REQUIRE script, to pick up variable settings
#
dot_file() {
    local dot_path

    PKG_SETUP_VARIABLES_ONLY=TRUE

    dot_path="$pkg_db_dir/$1$pkg_tag/+REQUIRE"
    trace Dotting file $dot_path ...

    if [ "$1$pkg_tag" = "$package" ]; then
	trace Dot file $dot_path is us
	if [ -r ./+REQUIRE ]; then
	    . ./+REQUIRE
	else
	    warn "Local requirements file for package $1 not found"
	fi
    elif [ ! -r $dot_path ]; then
	trace Dot file $dot_path does not exist
	if [ -z "$2" ]; then
	    warn "Could not open requirements file for $1$pkg_tag: $dot_path"
	fi
    elif grep -sq PKG_SETUP_VARIABLES_ONLY $dot_path; then
	. $dot_path
    else
	if [ -z "$2" ]; then
	    warn "Package '$1' is not compatible with package '$package':"
	    warn "    $1 does not support requirements tests (fatal)"
	    fail=1
	fi
    fi
}

#
# var_test <my-value> <test> <their-value>
#
var_test() {
    trace testing: "$@"

    _op="$2"
    case "$1$2$3" in
    *[\<\>.]*) _test=expr
	case "$_op" in
	-lt) _op="<";;
	-le) _op="<=";;
	-gt) _op=">";;
	-ge) op=">=";;
	-ne) op="!=";;
	-eq) op="=";;
	esac
	;;
    *) _test=test
	;;
    esac
    $_test "$1" "$_op" "$3" > /dev/null
}


#
# var_warn <my-name> <my-value> <test> <their-name> <their-value> <message>
#
# Warn (and bail) if the variables don't match
#
var_warn() {
    trace testing: "$@"

    if var_test "$2" "$3" "$5"; then
        warn "Package '$1' is not compatible with package '$4':"
        warn "    $6"
        warn "    ($1:$2 $_op $4:$5)"
        fail=1
    fi
}

#
# package_exists <package-name>
#
# return true if the package exists. Use this function for juniper packages
#
package_exists() {
    trace package_exists tests $1 `ls -ld /etc/db/pkg/$1$pkg_tag 2>/dev/null`
    if [ -d /etc/db/pkg/$1$pkg_tag ]; then
	trace package_exists: "$1" is installed
	true
    elif [ "$1$pkg_tag" = "$package" ]; then
	trace package_exists: "$1" is us
	true
    else
	trace package_exists: fails for "$1"
	false
    fi
}

#
# package_installed <package-name>
#
# return true if the package exists. Use this function for non-juniper
# packages.
#
package_installed() {
    trace package_installed tests $1 `ls -ld /etc/db/pkg/$1 2>/dev/null`
    if [ -d /etc/db/pkg/$1 ]; then
	trace package_installed: "$1" is installed
	true
    elif [ "$1" = "$package" ]; then
	trace package_installed: "$1" is us
	true
    else
	trace package_installed: fails for "$1"
	false
    fi
}

#
# package_does_not_exist <package-name>
#
package_does_not_exist() {
    if package_exists "$1" ; then
	false
    else
	true
    fi
}

daemon_restart_warn() {
    echo "WARNING: Daemons could not be restarted:" "$*"
}

#
# daemon_restart_other <daemon-name>
#
# Restart a daemon by means other than rpdc
#
daemon_get_pid() {
    if [ -r /var/run/$1.pid ]; then
	cat /var/run/$1.pid
    else	
	ps gax | grep "/$1 -N" | grep -v grep | awk '{ print $1 }' 2>/dev/null
    fi
}
                    
daemon_kill_other() {
  local daemon_pid=`daemon_get_pid "$@"`
  if [ ! -z "$daemon_pid" ]; then
      kill -TERM "$daemon_pid"
  fi
}

daemon_restart_other() {
    echo "Restarting $1 ..."
    daemon_kill_other "$@"
}

#
# daemon_restart <daemon-name>
#
# restart a daemon by whatever means available; normally, this means that
# we kill it (using rpdc is possible) and init restarts it
#
daemon_kill() {
    if [ -x /usr/sbin/rpdc ]; then
	rpdc -q -D$1 stop
    else
	daemon_kill_other $1
    fi
}

daemon_restart() {
    echo "Restarting $1 ..."
    daemon_kill "$@"
}

#
# daemon_is_running <daemon-name>
#
daemon_is_running() {
    if [ -x /usr/sbin/rpdc ]; then
	rpdc -q -D$1 running	
    else
	false
    fi
}


# record the fact that a package wants to reboot
package_wants_to_reboot() {
    DebugOn package_wants_to_reboot
    case "${need_to_reboot_rc:-false}" in
    false)
        warn "Package $1 wants to reboot${2:+: $2}"
        need_to_reboot_rc=true
        echo need_to_reboot_rc=true >> ${PKG_NEED_TO_REBOOT:-/dev/null}
        ;;
    esac
    DebugOff package_wants_to_reboot
}

#
# need_to_reboot
#
# Determine if we need to reboot after software install
#
need_to_reboot() {
    need_to_reboot_rc=${need_to_reboot_rc:-false}

    if [ "$need_to_reboot_rc" = true ]; then
        # we've been here before and already made up our mind
        return 0
    fi

    # someone else may have already decided...
    if [ -s ${PKG_NEED_TO_REBOOT:-/dev/null} ]; then
	. $PKG_NEED_TO_REBOOT
    fi

    #
    # If the running kernel has no +REQUIRE script variables,
    # it's an oldie and we definitely want to reboot.
    #
    dot_jkernel_require
    if [ ! -r $jkernel_require ]; then
        need_to_reboot_rc=true
    fi
    
    if package_exists jkernel ; then
	if [ -z "$jkernel_works" ]; then
	    dot_file jkernel quietly
	fi
	if [ ! -z "$jkernel_works" ]; then
	    if jkernel_needs_to_reboot ; then
		need_to_reboot_rc=true
	    fi
	fi
    fi

    if package_exists jbase ; then
	if [ -z "$jkernel_works" ]; then
	    dot_file jkernel quietly
	fi
	if [ ! -z "$jkernel_works" ]; then
	    if jkernel_needs_to_reboot ; then
		need_to_reboot_rc=true
	    fi
	fi
    fi

    if package_exists jroute ; then
	if [ -z "$jroute_works" ]; then
	    dot_file jroute quietly
	fi
	if [ ! -z "$jroute_works" ]; then
	    if jroute_needs_to_reboot ; then
		need_to_reboot_rc=true
	    fi
	fi
    fi

    if package_exists jpfe ; then
	if [ -z "$jpfe_works" ]; then
	    dot_file jpfe quietly
	fi
	if [ ! -z "$jpfe_works" ]; then
	    if jpfe_needs_to_reboot ; then
		need_to_reboot_rc=true
	    fi
	fi
    fi

    if package_exists jcrypto ; then
	if [ -z "$jcrypto_works" ]; then
	    dot_file jcrypto quietly
	fi
	if [ ! -z "$jcrypto_works" ]; then
	    if jcrypto_needs_to_reboot ; then
		need_to_reboot_rc=true
	    fi
	fi
    fi

    if [ "$need_to_reboot_rc" = true ]; then
        echo need_to_reboot_rc=true >> $PKG_NEED_TO_REBOOT
    fi
    $need_to_reboot_rc
}

#
# user_wants_reboot
#
# Does the user intend on rebooting after we exit? If so, there's no
# need to restart/rebuild/retool anything.
#
user_wants_reboot() {
    trace user_wants_reboot: $PKG_USER_WILL_REBOOT
    [ ! -z "$PKG_USER_WILL_REBOOT" ];
}

#
# user_wants_to_delay
#
# Does the user want to delay? This may be by choice, and may be
# because the software is not being installed into the running system.
#
user_wants_to_delay() {
    trace user_wants_to_delay: $PKG_USER_WANTS_TO_DELAY
    [ ! -z "$PKG_USER_WANTS_TO_DELAY" ];
}

#
# save_current_configuration
#
# If the database exists, we try to save it in ascii form using the
# previous package's mgd (mgd.last from POST-INSTALL). If the saved
# version if different that the last committed version, or if there
# is no committed version, let the user know where the save file is.
#
save_current_configuration() {
    DebugOn save_current_configuration
    local saving_mgd

    trace save_current_configuration

    if [ "x$PKG_SAVE_CURRENT_CONFIGURATION" != x ]; then
	# we've been here before.
	return
    fi
    if [ -f $mgd ]; then
	saving_mgd=$mgd
    else
	saving_mgd=$mgd_last
    fi

    if [ -f $config_database -a -x $saving_mgd ] ; then
	$saving_mgd -e $config_changes > /dev/null 2>&1
	if [ -f $config_changes ] ; then
	    if [ -f $config_file ] ; then
                case $config_file in
		*.gz) gunzip < $config_file | diff -q $config_changes - > /dev/null;;
		*) diff -q $config_file $config_changes > /dev/null;;
		esac
		if [ $? != 0 ]; then
		    notice "uncommitted changes have been saved in $config_changes"
		fi
	    else
		notice "uncommitted database has been saved in $config_changes"
	    fi
	fi
	# avoid doing this more than once
	echo PKG_SAVE_CURRENT_CONFIGURATION=: >> $PKG_NEED_TO_REBOOT
    fi
    DebugOff save_current_configuration
}

#
# restart_mgd
#
# We need to restart the management daemon, if possible. This involves
# rebuilding the schema, since the incoming package should have dd.so
# shared libraries that affect it. This operation implicitly reloads
# the configuration database. We then run a commit, to make the
# configuration really happen. Then we restart the mgd daemon itself.
#
restart_mgd() {
    local rc mgd_running
    trace restart_mgd

    [ $package = jroute -o -d $pkg_db_dir/jroute -o -z "$PKG_IS_JUNOS" ] ||  { 
	trace no jroute package
	return
    }
    [ -x $mgd ] || { trace $mgd not available; return; }

    # Save the old config binary database. If there is a committed
    # version, reload it. I don't reload the uncommitted changes.
    if [ -f $config_database ] ; then
	mv $config_database $config_database.old
    fi

    rc=false
    daemon_is_running mgd
    mgd_running=$?

    if [ -f $config_file ] ; then
	cp -p $config_file /var/db/$config_file.post-install
	echo "Reloading $config_file ..."
	$mgd build-schema
	if [ $? -ne 0 ]; then
	    warn "Errors found while loading configuration."
	    warn "Correct the errors and commit the configuration."
	    rc=true
	else 
	    echo "Activating $config_file ..."
	    $mgd activate
	    if [ $? -ne 0 ]; then
		rc=true
	    fi
	fi
    fi

    # mgd should be running already; stop it and init will restart it
    # If it wasn't running, kicking init should have started it for us.
    if [ $mgd_running = 0 ]; then
	daemon_restart mgd
    fi
    kill -HUP 1

    $rc
}

#
# restart_watchdog
# 
# Restart watchdog daemon
#
restart_watchdog () {
    local pid

    echo "Restarting watchdog ..."
    pid=`ps gax | grep "$1 -d" | grep -v grep \
	 | awk '{ print \$1 }' 2>/dev/null`
    if [ ! -z "$pid" ]; then
	kill -TERM "$pid"
    else
	warn "restart_watchdog: Watchdog process not found"
    fi
    #
    # HUP init for good measure
    kill -HUP 1
}

#
# all_packages_exist [quietly]
#
# Determine if we have a complete set of software
#
all_packages_exist() {
    local all_packages_exists_rc
    all_packages_exists_rc=true

    all_packages_exist_test jkernel $1
    all_packages_exist_test jroute $1
    all_packages_exist_test jpfe $1
    all_packages_exist_test jpfe-common $1
    $all_packages_exists_rc
}

all_packages_exist_test() {
    if package_does_not_exist "$1" ; then
	trace all_packages_exist: package_does_not_exist "$1"
	if [ -z "$2" ]; then
	    warn "Package "$1" is not installed"
	fi
	all_packages_exists_rc=false
    fi
}

warn_of_reboot() {
    if [ -z "$PKG_USER_WILL_REBOOT" ]; then
	# after we've been through here once, PKG_WARN_DELAY
	# will be ':' and so these lines will be commented out.
	$PKG_WARN_DELAY warn "A reboot is required to load this software correctly"
	# jbundle calls us with an arg of jboot if he needs to update
	# it, when this happens all_packages_exist will do the wrong thing
	# since we've not removed anything yet, so we skip it.
	if [ "$1" != jboot ] && all_packages_exist quietly ; then
	    $PKG_WARN_DELAY warn "    Use the 'request system reboot' command immediately"
	else
	    $PKG_WARN_DELAY warn "    Use the 'request system reboot' command"
	    $PKG_WARN_DELAY warn "        when software installation is complete"
	fi
    fi
    $PKG_WARN_DELAY echo PKG_WARN_DELAY=: >> $PKG_NEED_TO_REBOOT
    PKG_WARN_DELAY=:
}

#
# check_delay
#
#
check_delay() {
    if user_wants_reboot ; then
	trace check_delay: user_wants_reboot
	# hold your tongue
	true
    elif user_wants_to_delay ; then
	trace check_delay: user_wants_to_delay
	warn "Daemons will be restarted at a later time"
	true
    elif need_to_reboot ; then
	trace check_delay: need_to_reboot
        warn_of_reboot
	true
    else
	false
    fi
}

#
# kick_off_other_daemons <daemon-name> ...
#
# Restart whatever non-conformant daemons
#
kick_off_other_daemons() {
    local kick_list restart_list daemon

    if check_delay ; then
	trace kick_off_daemons: delaying
	# hold your tongue
	true
    else 
	restart_list="$*"
	trace kick_off_other_daemons: get to work
	# Restart daemons by stopping them and letting init restart them
	for daemon in $restart_list ; do
	    trace kick_off_other_daemons: restarting $daemon
	    daemon_restart_other $daemon
	done

	# HUP init once more just to be safe....
	kill -HUP 1

	false
    fi
}

#
# kick_off_daemons <daemon-name> ...
#
# Restart whatever daemons are required to get this thing cooking
#
kick_off_daemons() {
    local kick_list restart_list daemon

    if check_delay ; then
	trace kick_off_daemons: delaying
	# hold your tongue
	true
    elif package_does_not_exist jroute && [ -z "$PKG_NOT_JUNOS" ]; then
	trace kick_off_daemons: no jroute
	# after we've been through here once, PKG_WARN_RESTART_JROUTE
	# will be ':' and so these lines will be commented out.
	$PKG_WARN_RESTART_JROUTE warn "Daemons will be restarted when the jroute package is installed"
	$PKG_WARN_RESTART_JROUTE echo PKG_WARN_RESTART_JROUTE=: >> $PKG_NEED_TO_REBOOT
	PKG_WARN_RESTART_JROUTE=:
	false
    else 
	kick_list="$*"
	trace kick_off_daemons: get to work
	restart_list=""
	for daemon in $kick_list ; do
	    if [ "$daemon" = "mgd" ]; then
		# skip mgd
	    else
		daemon_is_running $daemon
		if [ $? -eq 0 ]; then
		    restart_list="$restart_list $daemon"
		fi
	    fi
	done

	if restart_mgd $kick_list; then
	    trace kick_off_daemons: restart_mgd failed
	    # Restarting mgd failed. We need to decide whether we
	    # can restart our daemons
	    # Don't do anything for now....
	    false
	else

	    # MGD should have just HUPped init
	    # kill -HUP 1

	    # Restart daemons by stopping them and letting init restart them
	    for daemon in $restart_list ; do
		trace kick_off_daemons: restarting $daemon
		daemon_restart $daemon
	    done

	    # HUP init once more just to be safe....
	    kill -HUP 1

	    false
	fi
    fi
}

#
# md5_cksum_value <file>
#
# Get the MD5 checksum value for a file 
#
md5_cksum_value() {
    md5 < "$1" 2>/dev/null
}

#
# what_filesystem <file>
#
# Determine which filesystem a given file is mounted on, if any
#
what_filesystem () {
    df $1 | grep -v Filesystem | awk '{print $1}' 2>/dev/null
}

#
# which <cmd-file>
#
# We don't ship /usr/bin/which, so we have to fake one
#
which() {
    local which_found
    which_found=""
    for dir in /sbin /usr/sbin /bin /usr/bin /usr/libexec ; do
	if [ -x "$dir/$1" -a -z "$which_found" ]; then
	    echo "$dir/$1"
	    which_found="done"
	fi
    done
}

#
# daemon_needs_restarted <daemon-name>
#
# Determine if the daemon needs to be restarted based on the md5 checksum
# of the running image and it's disk file
# Note that with packages mounted in ISO filesystems now, we could have
# the same file with matching MD5s but in two different filesystems - we
# to make sure we report true in this case
#
daemon_needs_restarted() {
    local pid daemon_md5 binary_file binary_md5 daemon_fs binary_fs

    if [ -r /var/run/$1.pid ]; then
	pid=`cat /var/run/$1.pid`
	if [ -r /proc/$pid/file ]; then
	    daemon_md5=`md5_cksum_value /proc/$pid/file`
	    binary_file=`which $1`
	    if [ -z "$binary_file" ]; then
	        trace "daemon_needs_restarted: no binary for $1"
		false
	    else
		binary_md5=`md5_cksum_value $binary_file`
		#
		# Ok, if their MD5s are the same, they could still be on
		# different filesystems, so let's check that as well
		if [ "$daemon_md5" = "$binary_md5" ]; then
 		    daemon_fs=`what_filesystem /proc/$pid/file`
		    binary_fs=`what_filesystem $binary_file`
		    [ "$daemon_fs" != "$binary_fs" ]
		else
		    true
		fi
	    fi
	else
	    #
	    # There was a pid file but we found no process with that pid...
	    # this is a race condition and init has restarted the daemon.
	    # We'll ask for a restart anyway.
	    #
	    trace "daemon_needs_restarted: pidfile but no process for $1"
	    true
	fi
    else
	trace "daemon_needs_restarted: no pidfile for $1"
	true
    fi
}

#
# consider_kicking_daemons <daemon-name> ...
#
# Consider each of the daemons given as arguments; if the running version
# is not the version on disk, restart it.
#
consider_kicking_daemons() {
    local kick_list daemon

    if user_wants_reboot ; then
	trace consider_kicking_daemons: user_wants_reboot
    elif user_wants_to_delay ; then
	trace consider_kicking_daemons: user_wants_to_delay
    elif need_to_reboot ; then
	trace consider_kicking_daemons: need_to_reboot
    elif [ ! -x $mgd ]; then
	trace consider_kicking_daemons: no mgd
    else 
	kick_list="$*"
	trace consider_kicking_daemons: get to work

	# Restart daemons by stopping them and letting init restart them
	for daemon in $kick_list ; do
	    trace consider_kicking_daemons: considering $daemon
	    if [ "$daemon" = "mgd" ]; then
		# skip mgd
	    elif daemon_needs_restarted $daemon; then
		trace consider_kicking_daemons: restarting $daemon
		daemon_restart $daemon
	    else
		rpdc -D$daemon reconfig
	    fi
	done
    fi
}

#
# create_mount_package
#   Create script to mount specified package
#
# args
# $1  - package-path to mount
# $2  - mount point for package

create_mount_package () {
    DebugOn create_mount_package
    local pkgpath mountpoint
 
    pkgpath=$1
    mountpoint=$2

    # We create a mount script that will stand being run twice during
    # boot. The first time, core packages should be mounted, but
    # optional ones - that have their .iso's on /var should silently
    # give up if the pkgpath isn't available.
    #
    # During the second pass - after /var is mounted, we don't want
    # to bleat about being already mounted, but we do want to complain
    # about any missing pkgpaths.
    # 
cat <<EOF
:
case "\$1" in
optional)
    core=:; optional=echo;;
*)  core=;  optional=:;;
esac
# for the benefit of cleanup-pkgs
pkgpath=$pkgpath
if [ ! -s $pkgpath ]; then
    pkgdir=`dirname $pkgpath`
    # if pkgdir is not present, we'll pick it up in second round
    # so keep quiet now
    if [ -d \$pkgdir ]; then
	echo $pkgpath not present.
    else
        \$optional echo \$pkgdir not present.
    fi
    exit 66			# EX_NOINPUT
fi
mounted=\`/sbin/mount | /usr/bin/grep " $mountpoint "\`
case "\$mounted" in
*/*) \$core echo $pkgpath already mounted; exit 0;;
esac

EOF
    if [ -x /sbin/mount_iso ]; then
        echo "exec /sbin/mount_iso --force $pkgpath $mountpoint $package"
    else
        # do it the old way
        # XXX this can go away when 6.3 is EOL
        cat << EOF
for hash in sha1 md5
do
    [ -s /sbin/\$hash ] || continue
    [ -s \$pkgpath.\$hash ] || continue

    want=\`cat \$pkgpath.\$hash\`
    have=\`\$hash < \$pkgpath\`
    if [ x\$have != x\$want ]; then
	logger -t mount_check -s -p daemon.alert "\`\$hash \$pkgpath\` != \$want"
    fi
    break
done

u=1
while [ \$u -lt 99 ]
do
    vnd=vn\$u
    if /sbin/vnconfig -q -c -s compressed \$vnd $pkgpath autoffset; then
        if /sbin/mount -t cd9660 -r /dev/\$vnd $mountpoint; then
	    echo "Mounted $package package on /dev/\$vnd..."

	    # look to see if this package has a special mount procedure
	    postmount=$mountpoint/mount.post

	    if [ -f \$postmount ]; then 
		echo "Executing \$postmount.."
		if \$postmount $mountpoint; then 
		    # all of our postmount goodness worked
		else 
		    # already complained, should return error and unmount
		    # do we want to /sbin/umount $mountpoint and then
		    # /sbin/vnconfig -u -v /dev/\$vnd as error handling?
		    exit 1
		fi
	    fi
            exit 0
	else
	    echo "Unable to mount $package on /dev/\$vnd"
            /sbin/vnconfig -u -v /dev/\$vnd
            exit 1
	fi
    fi
    u=\`expr \$u + 1\`
done
echo "Unable to mount $package - no more vn devices"
exit 1
EOF
    fi
    
    DebugOff create_mount_package
}

#
# Create script to unmount specified package
#
# $1 - mount point

create_umount_package () {
    DebugOn create_umount_package
    local pkgpath mountpoint

    pkgpath=$1
    mountpoint=$2

    if [ -x /sbin/umount_iso ]; then
        echo "exec /sbin/umount_iso $pkgpath $mountpoint $package" 
    else
        # do it the old way
        # XXX this can go away when 6.3 is EOL
        cat << EOF
for hash in sha1 md5
do
    [ -s /sbin/\$hash ] || continue
    [ -s \$pkgpath.\$hash ] || continue

    want=\`cat \$pkgpath.\$hash\`
    have=\`\$hash < \$pkgpath\`
    if [ x\$have != x\$want ]; then
	logger -t mount_check -s -p daemon.alert "\`\$hash \$pkgpath\` != \$want"
    fi
    break
done
/sbin/mount | /usr/bin/grep " $mountpoint " |
while read vnd junk
do
    # look to see if this package has a special unmount procedure
    preumount=$mountpoint/umount.pre

    if [ -f \$preumount ]; then 
	if \$preumount $mountpoint; then 
	    # all of our pre-umount goodness worked
	else 
	    # already complained, not much we can do other than try to 
	    # deconfigure anyway
	fi
    fi

    if /sbin/umount $mountpoint; then
        echo "Unmounted $mountpoint ..."
        /sbin/vnconfig -u -v \$vnd || echo "Unable to unconfigure \$vnd"
    else 
        # this can happen if MGD has a DDL SO from the package loaded.. 
    fi
done
EOF
    fi
    
    DebugOff create_umount_package
}

#
# Create links for package related scripts/mounts
#
make_package_links () {
    DebugOn make_package_links
    /bin/mkdir -p $mountdir
    /bin/rm -df $base_mountdir
    make_symlink ${mountdir##*/} $base_mountdir 
    if [ $base_pkgdir = $pkgdir ]; then
	make_symlink $pkgfile $base_pkgdir/$package
    else
	make_symlink $pkgdir/$pkgfile $base_pkgdir/$package
    fi
    if [ -s $mountpkg ]; then
	make_symlink ${mountpkg##*/} $base_mountpkg
	/bin/chmod 0755 $mountpkg
	make_symlink ${umountpkg##*/} $base_umountpkg 
	/bin/chmod 0755 $umountpkg
    fi
    DebugOff make_package_links
}

#
# check_installed
#
# Check to see if this exact version of this package is already installed
#
check_installed () {
    local pkglink

    if [ -d /etc/db/pkg/$package -a -f $pkgdir/$pkgfile -a -d $mountdir ]; then
        case `/bin/ls -l $base_mountdir` in
	*"> $mountdir")
	    warn "This version of $package is already installed on this system"
	    return 0
            ;;
	esac
    fi
    false
}

check_junos_reboot_pending() {
    if [ -s $junos_reboot_pending ]; then
        error_more "There is already an install pending."
        error_more "    Use the 'request system reboot' command to complete the install,"
        error "    or the 'request system software rollback' command to back it out."
    fi
}    


#
# get_lock [lock] [iflocked]
# Implements mutual exclusion based on content of "lock"
# If we return from here then we have the mutex.
# If iflocked is "waitfor" we will wait for the current locker to exit
# and retry rather than simply exit with $iflocked as status (default 1).
#
get_lock() {
	lock=${1:-$pkg_LCK}
	iflocked=${2:-1}
	tlock=$lock.$$
	ltty=`expr ${CLI_TTY:-__} : '.*\(..\)$'`
	case $ltty in
	__) ltty=unknown;;
	esac
	ldate=`date "+%Y-%m-%d %H:%M %Z"`

	while :
	do
		lpid=
		echo "lpid=$$ ldesc=\"user ${CLI_USER:-unknown} terminal $ltty, process $$, started at $ldate\"" > $tlock
		ln $tlock $lock > /dev/null 2>&1 && break
		rm -f $tlock	# avoid mess
		# 
		# we are going to eval the content of the lock
		# but _not_ if it contains anything other than what we expect
		#
		xl=`test -s $lock && grep -i '^lpid=[0-9][0-9]* ldesc="[a-z][a-z0-9:, -]*"$' $lock`
		case "$xl" in
		lpid=*)	eval $xl;;
		esac
		case "$lpid" in
		"")	# an empty or invalid lock file should never happen
			rm -f $lock; test -f $lock || continue
			error "cannot remove empty lock '$lock'"
			;;
		esac
		# we can't simply use return code, as permission denied means
		# locker is alive... watch out for internationalization!
		psts=`LANG=C LC_ALL=C kill -0 $lpid 2>&1`
		case "$psts" in
		*:*such*p*)
			rm -f $lock; test -f $lock || continue
			error "cannot remove old lock '$lock' held by $ldesc"
			;;	    
		esac
		# ok a valid lock exists, and it isn't us
		case "${iflocked:-1}" in
		waitfor)
		    # we want to wait for the lock, as long as it takes...
		    while :
		    do
			psts=`LANG=C LC_ALL=C kill -0 $lpid 2>&1`
			case "$psts" in
			*:*such*p*) rm -f $lock; break;;
			esac
			sleep 8
		    done
		    continue
		    ;;
		0)  # go quietly
		    Exit 0
		    ;;
		[1-9]*)
		    echo "ERROR: Another package installation in progress:"
		    echo $ldesc
		    Exit ${iflocked:-1}
		    ;;
		esac
	done
	rm -f $tlock
}
	    
fi # Close the 'if' from the top of the file (PKG_SETUP_VARIABLES_ONLY)
#!/bin/sh
#
# $Id: script-funcs,v 1.12 2006/08/10 08:32:50 builder Exp $
#
# Copyright (c) 1999-2006, Juniper Networks, Inc.
# All rights reserved.
#

#
# SHA1 is better than MD5, use it if available
# HASH_CMD is the command we run
# HASH_EXT is the .ext (sans .)
# HASH_NAME is the official name of the hash
#
if [ -x /sbin/sha1 ]; then
    HASH_CMD=sha1
    HASH_EXT=sha1
    HASH_NAME=SHA1
else
    HASH_CMD=md5
    HASH_EXT=md5
    HASH_NAME=MD5
fi

# atexit.sh will provide this, but have it here to so we
# can use it without atexit
Exit() {
	ExitStatus=$1
	exit_sts=$1
	exit $1
}

# from debug.sh

DEBUGGING=
DEBUG_DO=:
DEBUG_SKIP=
export DEBUGGING DEBUG_DO DEBUG_SKIP

_debugOn() {
	DEBUG_OFF=
	DEBUG_DO=
	DEBUG_SKIP=:
	set -x
	DEBUG_ON=$1
}

_debugOff() {
	DEBUG_OFF=$1
	set +x
	DEBUG_ON=$2
	DEBUG_DO=:
	DEBUG_SKIP=
}

# Turn on debugging if appropriate
DebugOn() {
	local e

	case "${DEBUG_SH:-$DEBUG}" in
	"")	return 1;;
	esac
	# if debuggin is off because of a !e
	# don't add 'all' to the On list.
	case "$DEBUG_OFF" in
	"")	e=all;;
	*)	e=;;
	esac
	for e in ${*:-$Myname} $e
	do
		case ",${DEBUG_SH:-$DEBUG}," in
		*,!$e,*|*,!$Myname:$e,*)
			# only turn it off if it was on
			$DEBUG_DO _debugOff $e $DEBUG_ON
			return 0
			;;
		*,$e,*|*,$Myname:$e,*)
			# only turn it on if it was off
			$DEBUG_SKIP _debugOn $e
			return 0
			;;
		esac
	done
	return 1
}

# Only turn debugging off if one of our args was the reason it
# was turned on.
DebugOff() {
	local e

	for e in $*
	do
		case "$DEBUG_OFF" in
		"")	break;;
		$e)	_debugOn $DEBUG_ON; return 0;;
		esac
	done
	for e in $*
	do
		case "$DEBUG_ON" in
		"")	break;;
		$e)	_debugOff; return 0;;
		esac
	done
	return 0		# always happy
}

# return the first of $* that exists
# we generally use this to deal with expanding wildcards.
Exists() {
    case "$1" in
    -?) _t=$1; shift;;
    *) _t=-s;;
    esac
    for f in $*
    do 
	[ $_t $f ] || continue
	echo $f
	break
    done
}

# a boolean form of Exists
exists() {
    case "$1" in
    -?) _t=$1; shift;;
    *) _t=-s;;
    esac
    for f in $*
    do 
        [ $_t $f ] && return 0
    done
    return 1
}

# make it easier to add per-package tweaks without having to
# re-introduce cut/paste hell.
run_hooks() {
    eval __h="\$$1"
    for e in $__h
    do
        $e
    done
}

read_link() {
    if [ -h $1 ]; then
        /bin/ls -l $1 | sed -e 's,.*-> ,,' -e 's,.*/,,'
    else
        echo $1
    fi
}

# make_symlink <src> <target>
#
# if <target> does not already point at <src>
# make the link.
# The goal is to minimize writes to the flash

make_symlink() {
    DebugOn make_symlink make_symlink:$1 make_symlink:$2
    local src target target_dir
    src=$1 
    target=$2

    if [ -h $DESTDIR$target ]; then
        case `/bin/ls -l $DESTDIR$target` in
	*"> $src")
            trace "make_symlink: ok: $DESTDIR$target -> $src"
	    DebugOff make_symlink make_symlink:$src make_symlink:$target
            return;;
	esac
    fi
    trace "make_symlink: making: $DESTDIR$target -> $src"
    target_dir=`dirname $DESTDIR$target`
    [ -d $target_dir ] || mkdir -p $target_dir
    /bin/ln -sf $src $DESTDIR$target
    DebugOff make_symlink make_symlink:$src make_symlink:$target
}

# make_symlinks <package-name>
#
# If the file symlinks exists, we compare it to
# the one for the previous version of <package-name>
# and implement any changes.

make_symlinks() {
    DebugOn make_symlinks make_symlinks:$package make_symlinks:$1
    local symlinks old_symlinks tf

    symlinks=${1:-./$package.symlinks}
    old_symlinks=${2:-$pkgdir/$package.symlinks}
    tf=/tmp/sl$$

    if [ -s $symlinks ]; then
        if [ -s $old_symlinks ]; then
	    # make sure we don't trip over changed flags
	    # cut(1) would be nice
	    awk '{ print $1, $2 }' $symlinks | sort -u > $tf.new
	    awk '{ print $1, $2 }' $old_symlinks | sort -u > $tf.old
            # get rid of links which may no longer be correct
            diff -b $tf.old $tf.new | while read op src target
	    do
                case "$op" in
		"<") # delete - but only if it still points at src
                     # and isn't no_unlink (in either list)
                     case `grep " $target .*no_unlink" $symlinks $old_symlinks` in
		     *no_unlink*) continue;;
		     esac
                     if [ -h $DESTDIR$target ]; then
                         case `/bin/ls -l $DESTDIR$target` in
			 *"> $src")
                             trace "make_symlinks: removing: $DESTDIR$target -> $src"
                             /bin/rm -f $DESTDIR$target
                             ;;
			 esac
		     fi
                     ;;
		esac
            done
	fi
        # make sure that the ones that should be there, are.
        while read src target flags
	do
	    make_symlink $src $target
        done < $symlinks
    fi
    DebugOff make_symlinks make_symlinks:$package make_symlinks:$1
}

# Override these if need be
warn() {
    if [ -z "$1" ]; then
	echo 
    else
	echo "WARNING: $@"
    fi
}

# more error to follow, don't die yet
error_more() {
    if [ -z "$1" ]; then
	echo 
    else
	echo "ERROR: $@"
    fi
}

error() {
    error_more "$@"
    ${PKG_FORCE:+:} Exit 1
}

# like error - but we don't allow PKG_FORCE to keep us from dying
Error() {
    error_more "$@"
    Exit 1
}

notice() {
    if [ -z "$1" ]; then
	echo 
    else
	echo "NOTICE: $@"
    fi
}

inform() {
    if [ -z "$PKG_QUIET" ]; then
	echo "$@"
    fi
}


#
# trace <args>
#
# make a trace message
#
trace() {
    if [ ! -z "$PKG_TRACE_ENABLED" ]; then
	echo "trace: $@"
    fi
}

#
# verify_hash hash
#
# If there is a file "hash" we check that
# "hash_cmd" < "pkg" == `cat "hash"`
# We determine "hash_cmd" from the extention of "hash"
# and "pkg" is "hash" with its ."hash_ext" extention stripped.
#
verify_hash() {
    DebugOn verify_hash
    local pkg hash hash_cmd hash_desc hash_ext want have
    local rc=1
    local dir base certs

    hash=$1

    if [ -s $hash ]; then
	case "$hash" in
	*sig) # real signature file
	    hash_cmd=/sbin/verify-sig
	    ;;
	*md5)  hash_cmd=/sbin/md5
	    hash_ext=md5
	    hash_name=MD5
	    ;;
	*sha1)	hash_cmd=/sbin/sha1
	    hash_ext=sha1
	    hash_name=SHA1
	    ;;
	esac

	if [ -x $hash_cmd ]; then
	    case "$hash" in
	    *sig)
		dir=`dirname $hash`
		base=`basename $hash .sig`
		certs=`Exists $dir/$base.certs $dir/certs.pem`
		$hash_cmd -b -c $certs $hash || Exit 1
		rc=0
		;;
	    *)
		# We rely on foo.tgz.$hash_ext being the $method hash
		pkg=`expr $hash : "\(.*\).$hash_ext"`

		want=`cat $hash`
		have=`$hash_cmd < $pkg`
		if [ "$have" = "$want" ]; then
		    inform Verified $hash_name checksum of $pkg
		    rc=0
		else
		    error Failed $hash_name checksum of $pkg
		    # ensure we do not proceed - even with PKG_FORCE set.
		    Exit 1
		fi
		;;
	    esac
	fi
    fi
    DebugOff verify_hash
    return $rc
}

verify_files() {
    DebugOn verify_files

    for f in $*
    do
	[ -s $f ] || continue
	case $f in
	*.sha1|*.md5|*.sig)
	    verify_hash $f
	    ;;
	*)
	    for h in $f.sig $f.sha1 $f.md5
	    do
		    verify_hash $h && break
	    done
	    ;;
	esac
    done	    
    DebugOff verify_files
}

# compensate for lack of cmp(1)
cmp() {
    case "$1" in
    -s) shift;;
    esac
    diff $* > /dev/null 2>&1
}

#
# replace $file with $file.new if appropriate 
#
install_if_new() {
    local file=$1
    local new=${NewExt:-new}
    local old=${OldExt:-old}
    
    if [ -s $file.$new ]; then
	if [ -f $file ]; then
	    if cmp -s $file $file.$new; then
		rm -f $file.$new
	    else
                rm -f $file.$old
                mv $file $file.$old
	    fi
        fi
    else
        rm -f $file.$new
    fi
    if [ -s $file.$new ]; then
        mv $file.$new $file
        :
    fi
}

# wrap output of $func in output tags after escaping
# any <>&. Eg. if main function is called main:
# xml_output main "$@"
xml_output() {
    local func rc

    func=$1; shift
    # dup 3 to stdout so we can avoid a temp file.
    # we'll send stdout of the child to 3, and
    # capture just what the child writes to fd 4.
    exec 3>&1
    rc=`(
	# we trap but ignore these signals
	# in the child that runs $func they will be reset to default
	trap : 1 2 3
	echo "<output>"

	# Use a sed -n ... -e 'w/dev/stdout'
	# kludge to work around buffered stdio
	{ (exec 3>&- 4>&-; $func "$@") 2>&1; echo $? >&4; } |
		sed -n -e 's,&,\&amp;,g' -e 's,<,\&lt;,g' -e 's,>,\&gt;,g' -e 'w/dev/stdout'

	echo "</output>"
    )  4>&1 1>&3`
    exec 3>&-
    return ${rc:-1}
}

# these are always handy, spacefor.c handles huge filesystems better
# but we don't generally have that issue.
file_size() {
    du -k -s $1 2> /dev/null | ( read sz junk; echo $sz )
}

space_on() {
    if [ -d $1 ]; then
	df -k $1 | (
	    while read fs blocks used avail rest
	    do
		case $avail in
		Av*) continue;;
		*) echo $avail; break;;
		esac
	    done
	)
    else
	echo 0
    fi
}

# dir=$1 want=$2
# want can be a number or a file
space_for() {
    [ -f $2 ] && _want=`file_size $2` || _want=$2
    _avail=`space_on $1`
    [ ${_avail:-0} -ge ${_want:-0} ]
}
#
# $Id: DEINSTALL,v 1.8 2005/02/22 19:16:33 rjohnst Exp $
#
# Copyright (c) 2003-2004, Juniper Networks, Inc.
# All rights reserved.
#
# Online Documentation Package additional de-installation script
#
# This script is run at the various stages of the package deinstallation.
#
# This file is appended to src/juniper/package-scripts/script-header
# to make the real DEINSTALL script. See that file for additional comments.
#

initialize "$@"

trace "STAGE = $instance"

if [ "$instance" = "DEINSTALL" ] ; then
    package_deinstall
fi

if [ "$instance" = "POST-DEINSTALL" ] ; then
    # Kill off daemons
    daemon_kill httpd
    
    if [ -L $jaillink ]; then 
	rm -f /jail
    fi

    package_post_deinstall
fi

exit $fail
