#!/bin/sh
#
# $Id: script-header,v 1.89.2.6 2007/12/11 19:58:22 mivanov Exp $
#
# Copyright (c) 1999-2007, 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
        for f in $pkgfile $pkgfile.md5 $pkgfile.sha1 $pkgfile.sig; do
           [ -f .$base_pkgdir/$f ] && cp -p .$base_pkgdir/$f $pkgdir && chflags schg $pkgdir/$f
        done
    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 $pkgdir/$pkgfile.sig >/dev/null 2>&1
    /bin/rm -f $pkgdir/$pkgfile $pkgdir/$pkgfile.md5 $pkgdir/$pkgfile.sha1 $pkgdir/$pkgfile.sig $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

    if [ -s /etc/rc.fips ]; then
        # fips package installed, remove all non-fips packages from /cf/packages
        for f in /cf/packages/j*
        do
            case $f in
            */junos*) continue;;
            */jpfe*) continue;;
            *\*) continue;;
            esac
            chflags noschg $f
            rm -f $f
        done
    fi 

    #
    # note that this will never match jbase - that only gets
    # unmounted at reboot time
    #
    # don't include anything that's a memfs or a devfs here, that's
    # a submount for a mounted package
    #
    # Also ignore '/jail/var' - that is an important nullfs mount for J-Web
    #
    mount | sed -n -e "/ufs,/d" -e "/devfs,/d" -e "/\/jail\/var/d" -e "/mnt\/$pkgmatch/s,mnt/,mnt ,p" |
    while read mddev j1 j2 mounted_package j3
    do
	# this helps debug issues...
	: mddev=$mddev 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
            mdconfig -d -u ${mddev##*md} >/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.5R4.4.
    # 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=junos-jseries-8.5R4.4-domestic.tgz
    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|jsr
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

    # Don't accept JSR image to load on pepsi class boxes , i.e
    # j2300, j4300, j6300. however we do accept it for in house
    # development.
    jsr:jsr[1-9][0-9]00:*|jsr:j[1-9][0-9]00:*)
        perms=$(expr $(smbc -o 0x30 0x57 1 | tail -1) : '.*\([0-9a-f]\)$')
        case $perms in
        2) 
        ;; # ok
        *)
        Error "Unsupported platform $product_model for JUNOS JS," \
              "use a jseries package"
        ;;
        esac
        ;;
    jseries:jsr[1-9][0-9][0-9][0-9]:*) ;; # ok
    jsr:jsr[1-9][0-9][0-9][0-9]:*) ;; # ok
    jsr:j[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
    local current=`sed 's,.*\[\([1-9][0-9.]*\).*,\1,' /etc/db/pkg/junos/+COMMENT`
    local min_release=${1:-8.5}
    
    if expr ${current:-0.0} \< $min_release > /dev/null; 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 $min_release or newer first.  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_send_signal()
{
  local daemon_pid=`daemon_get_pid "$2"`
  if [ ! -z "$daemon_pid" ]; then
      kill -$1 "$daemon_pid"
  fi
}

daemon_restart_other() {
    echo "Restarting $1 ..."
    daemon_send_signal TERM "$1"
}

#
# 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() {
    local rc
    if [ -x /usr/sbin/rpdc ]; then
	rpdc -q -D$1 stop
	rc=$?
    else
        rc=69			# unavailable
    fi
    if [ $rc = 69 ]; then
	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 && return 0
    fi
    false
}


# 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
	error "Cannot find /sbin/mount_iso!"
    fi
    echo "exec /sbin/mount_iso --force $pkgpath $mountpoint $package"
    
    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
	error "Cannot find /sbin/umount_iso!"
    fi
    echo "exec /sbin/umount_iso $pkgpath $mountpoint $package"

    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
}

check_sdk_version()
{
	if [ -z "$current_sdk_version_major" ]; then
		dot_run_require jbase
		dot_run_require junos
		current_sdk_version_major=${current_junos_sdk_version_major:-$current_jbase_sdk_version_major}
		current_sdk_version_minor=${current_junos_sdk_version_minor:-$current_jbase_sdk_version_minor}
		current_sdk_compat=${current_junos_sdk_compat:-$current_jbase_sdk_compat}
	fi
 
	if [ ${current_sdk_version_major:-0} != 1 ] || [ ${current_sdk_version_minor:-0} -lt 0 ]; then
		error "JUNOS version incompatible - supported version ${current_sdk_compat:-0.0} - current"
	fi
}
	    
fi # Close the 'if' from the top of the file (PKG_SETUP_VARIABLES_ONLY)
#!/bin/sh
#
# $Id: script-funcs,v 1.15 2007/02/01 22:25:42 nuke Exp $
#
# Copyright (c) 1999-2007, 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
}

#
# get_provider cert
#
# print the provider name of the certificate
# exit if the provider name doesn't match the common name prefix
#
get_provider() {
    local provider_name="jnxProviderName"

    /sbin/x509-exts -c $provider_name "$@"
    [ $? = 0 ] || Exit 1
}

#
# 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
    local extensions_allow="/var/etc/extensions.allow"

    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

		# Figure out the provider name of the signer cert
		PKG_PROVIDER_NAME=`get_provider $certs`
		if [ "$PKG_PROVIDER_NAME" ]; then
		    # it better be in extensions.allow
		    if ! grep -q "^$PKG_PROVIDER_NAME\$" $extensions_allow; then
			Error Packages from $PKG_PROVIDER_NAME are not allowed
		    fi
		fi
		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} ]
}
#!/bin/sh
#
# $Id: INSTALL,v 1.28 2007/05/07 21:14:22 sjg Exp $
#
# Copyright (c) 2001-2004, 2006-2007, Juniper Networks, Inc.
# All rights reserved.
#
# OS Update package installation script
#

initialize "$@"

tmppersistconf=/tmp/persistconf$$

save_loader_conf() {
    if [ -s /boot/loader.conf ]; then
        cat /boot/loader.conf | grep -e 'ata' -e 'cid' -e 'retype' -e 'model'
    fi > $tmppersistconf
}

restore_loader_conf() {
    if [ -s $tmppersistconf ]; then
        cat $tmppersistconf >> /boot/loader.conf
    fi
}

# If the existing system is different to us,
# the ssh keys need to be regenerated.
check_edition() {
    if [ -d $pkg_db_dir/jcrypto ]; then
        old=domestic
    elif [ -d $pkg_db_dir/jbase ]; then
        old=export
    else
        old=`sed -n -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' -e '/edition/s,.*(\(..*\) edition.*,\1,p' $pkg_db_dir/junos/+COMMENT 2>/dev/null`
        old=${old:-domestic}
    fi
    if [ -d /etc/ssh ]; then
	# just in case someone installs wrong one followed by
	# correct one - don't wack their keys.
	action='rm -f'
	if [ $old != "domestic" ]; then
	    case "domestic:$old" in
	    fips:*|*export*)
		warn "JUNOS edition domestic != $old, need to regenerate ssh host keys"
		action=touch
		;;
	    esac	
	fi
	eval $action /etc/ssh/regen-keys
    fi
    case "domestic:$old" in
    fips:*)
        # we cannot boot from removable media, so clean the bootdevs
        # list if needed.
        bdevs=`sysctl -n machdep.bootdevs`
        nbdevs=
        for bd in `IFS=,; echo $bdevs`
        do
            case "$bd" in
            lan)
                # known bad bad guys, remove silently
                continue
                ;;
            removable-compact-flash|usb|pcmcia*)
                # this one we need to keep - but with a restriction
                notice "$bd requires a tamper-proof label"
                ;;
            disk|*compact-flash) ;;     # known good guys
            *)  # unknown device, remove with warning
                warn removing $bd from boot devices
                continue
                ;;
            esac
            nbdevs="${nbdevs:+$nbdevs,}$bd"
        done
        if [ "$nbdevs" != "$bdevs" ]; then
            warn "Setting boot devices to: $nbdevs"
            sysctl -w machdep.bootdevs=$nbdevs > /dev/null 2>&1
        fi
        ;;
    *:fips)
        notice "Restoring default boot devices"
        sysctl -w machdep.bootdevs=default > /dev/null 2>&1
        ;;
    esac
}

if [ "$instance" = "POST-INSTALL" ] ; then
    # some folk don't know when to stop...
    [ -z "$PKG_FORCE" ] || platform_check jseries

    # we are not a normal package...
    pkgfile=junos-jseries-8.5R4.4-domestic
    jboot=junos-boot-jseries-8.5R4.4.tgz
    junos=junos-8.5R4.4-domestic
    jpfe=jpfe-8.5R4.4.tgz
    preinstall=/var/tmp/preinstall

    securelevel=`/sbin/sysctl -n kern.securelevel 2>/dev/null`
    if [ ${securelevel:-1} -lt 1 ]; then
        # If we're FIPS, signatures have already been checked.
        # Otherwise don't proceed unless everything is usable.
        for hash in *.$HASH_EXT
        do
            verify_files ${hash%.$HASH_EXT}
	done
    fi
    if [ -f $pkgdir/$junos ]; then
	warn "$junos is already installed,"
	warn "moving it aside."
	(cd $pkgdir
	chflags noschg $junos*
	rm -f ${junos}_old*
	for e in "" .sha1 .md5
	do
	    mv $junos$e ${junos}_old$e
	done
	chflags schg $junos*
	for j in junos junos.old
	do
	    case `/bin/ls -l $j` in
	    *$junos) ln -sf ${junos}_old $j;;
	    esac
	done)
    fi

    [ "$PKG_VALIDATING" ] || check_edition
    
    if [ -d /cf ]; then
        # There's nothing very tricky about jboot anymore
        # we can just update now.
        trace Updating jboot...
        save_loader_conf

        chflags noschg /cf/sbin/preinit.bak 2> /dev/null
        rm -f /cf/sbin/preinit.bak
        if exists /usr/lib/libc.so.4; then
            # we are upgrading from an incompatible version
            # save preinit for rollback...
            mv /cf/sbin/preinit /cf/sbin/preinit.bak
        fi
        tar --unlink -zxpf $jboot -C /cf || fail=1
        restore_loader_conf
        # the tar command does not fix the permissions of existing dirs
        chmod 1777 /cf/var/tmp
        chmod 0775 /cf/var/log
    else
        # We must be transitioning to the new layout.
        # an extra reboot is required...
        mkdir -p $preinstall
        mv $jboot $preinstall
        cp ./+install.junos /packages/finish-install.jboot
        case `grep rtld= /etc/rc` in
        "") ;; # /etc/rc has been cleaned of the old 5.3 downgrade logic
        *)  # cause preinit to mount jbase on its alternative mount
            # else, /etc/rc will create this and reboot again.
            mkdir -p $pkgdir_mnt/jbase_mnt
            ;;
        esac
        echo 'autoboot_delay="2"' >> /boot/loader.conf
        warn Need to cleanup old jboot
        warn_of_reboot jboot
        warn The update process will automatically reboot again when done
        echo
    fi

    if [ ${fail:-0} != 0 ]; then
        # someone probably used pkg_add -f
        warn_abort
    fi

    if [ -z "$PKG_VALIDATING" -a -s $jpfe ]; then
        # we mv this to /var/sw/pkg/ and mount_jpfe
        # will install it after we reboot, so as to maintain
        # the atomic nature of our upgrades.
        mkdir -p /var/sw/pkg
        mv ${jpfe}* /var/sw/pkg
        have_jpfe=
    else
        have_jpfe=:
    fi

    if expr ${PKG_VALIDATING:-0} \>= 8.5 > /dev/null; then
        # We have nothing left to do...
        Exit $fail
    fi
    # updating "junos" is trivial (preinit looks for junos-*)
    # we mv rather than cp because we very likely don't have space!
    mv $pkgfile $pkgdir/$junos
    mv $pkgfile.md5 $pkgdir/$junos.md5
    mv $pkgfile.sha1 $pkgdir/$junos.sha1
    chflags schg $pkgdir/$junos $pkgdir/$junos.md5 $pkgdir/$junos.sha1
    booted=`sysctl -n kern.bootfile`
    case "$booted" in
    *.old) # we are running junos.old - leave it alone!
        rm -f $pkgdir/junos	# this one is toast.
        ;;
    *)	# we don't need junos.old, the current junos will replace it.
        rm -f $pkgdir/junos.old
        ;;
    esac
    # this is our backup kernel!
    [ -f $pkgdir/junos ] && mv $pkgdir/junos $pkgdir/junos.old
    ln -sf $junos $pkgdir/junos
    if [ -z "$PKG_BOOTSTRAP" ]; then
        echo "JUNOS 8.5R4.4 will become active at next reboot"
        $have_jpfe echo $jpfe will be installed after next reboot
        warn_of_reboot
    fi
    cat $pkgdir/$junos.sha1 > $junos_reboot_pending
fi
ExitStatus=$fail
exit $fail
