#!/bin/sh
#
# $Id: script-header,v 1.2 2011/08/05 21:33:16 emil Exp $
#
# Copyright (c) 1999-2013, 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
product_model=${product_model:-`sysctl -n hw.product.model`}
case "$product_model" in
ex-xre*|ex[2-8]*) pkg_tag=-ex;;
               *) pkg_tag=;;
esac
fail=0
sw_pkgdir=/var/sw/pkg
opt_pkgdir=/opt/sdk/pkg
pkg_unsup=/etc/notices/unsupported.txt
pkg_supported_ltrs=ABRSWX

# 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 target_dir target_base 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
	    if [ "$ONLY_IF_MINE" = 1 ]; then
		# Remove the link only if jinstall-ex owns it
		local tgtf=`echo $target | sed 's,^//,/,'`
		local pkg=`ls -l $tgtf | sed -n 's,.*'$pkgdir_mnt'/\(.[^/]*\).*,\1,p'`
		if [ "$pkg" = "jinstall-ex" ]; then
		    /bin/rm -f $DESTDIR$target
		fi
	    else
		/bin/rm -f $DESTDIR$target
	    fi
	done < $old_symlinks
    fi
    DebugOff rm_symlinks
}

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

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

register_unsupported_package() {
    local signer sig

    if [ -s "$pkgdir/$pkgfile.esig" ]; then
	sig=$pkgdir/$pkgfile.esig
    else
	sig=$pkgdir/$pkgfile.sig
    fi
    # Only do this for non-release builds
    # Also avoid it for sdk-produced packages from third parties
    # (tricky because jservices-* look a lot like sdk packages...)
    signer=`sed -ne '1s,/.*CN=\([^/][^/]*\).*,\1,p' $sig 2>/dev/null`
    case R,$signer in
    [$pkg_supported_ltrs],*) ;;
    ?,Package*)
	echo Registering $package as unsupported
	ln -sf $pkg_unsup $pkg_db_dir/$package
	;;
    *)  ;;	# not for SDK built packages

    esac
}

# 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() {
    local old_destdir
    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.esig \
		$pkgfile.sig \
		$pkgfile.ecerts \
		$pkgfile.certs; do
           [ -f .$base_pkgdir/$f ] && cp -p .$base_pkgdir/$f $pkgdir && chflags schg $pkgdir/$f
        done
    fi
    old_destdir=${DESTDIR}
    DESTDIR=${DESTDIR:-$PKG_PREFIX}
    make_symlinks
    if [ -s ./$package.symlinks ]; then
        # will need these later
        trace installing $pkgdir/$package.symlinks
        cp -p ./$package.symlinks $pkgdir/$package.symlinks
        # modify the symlinks to have the proper package prefix path
        [ "$old_destdir" != "$DESTDIR" ] && sed -i '' "s, , $DESTDIR," $pkgdir/$package.symlinks
    fi
    DESTDIR=$old_destdir
    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

    register_unsupported_package

    DebugOff package_post_install
}

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

package_post_deinstall() {
    DebugOn package_post_deinstall
    run_hooks package_post_deinstall_hooks
    case "$package" in
    jbase|jbase-ex|jroute|jroute-ex|jkernel|jkernel-ex|jpfe*|jdocs|jruntime*)
        [ "$PKG_FORCE" ] || { DebugOff package_post_deinstall; return; }
        ;;
    esac
    case "$package" in
    jkernel|jkernel-ex)
        /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.esig \
	    $pkgdir/$pkgfile.sig \
	    $pkgdir/$pkgfile.ecerts \
	    $pkgdir/$pkgfile.certs >/dev/null 2>&1

    /bin/rm -f $pkgdir/$pkgfile \
	    $pkgdir/$pkgfile.md5 \
	    $pkgdir/$pkgfile.sha1 \
	    $pkgdir/$pkgfile.esig \
	    $pkgdir/$pkgfile.sig \
	    $pkgdir/$pkgfile.ecerts \
	    $pkgdir/$pkgfile.certs \
	    $pkgdir/$package \
	    $pkgdir/$package.symlinks

    if [ -z "$PKG_UPGRADE" ]; then
	if ! need_to_reboot; then
	    [ "$HasDDL" ] && restart_mgd
	    [ "$HasKillDaemons" ] && kick_off_other_daemons $HasKillDaemons
	fi
    fi
    DebugOff package_post_deinstall
}

junos_boot_from_iso () {
    local isover
    isover=`read_link $1 | sed -e 's,junos-,,' -e 's,-domestic,,' -e 's,-export,,' -e 's,-fips,,'`

    ls /var/sw/pkg/junos-boot-*-$isover.tgz 2> /dev/null
}

# Kill anyone keeping an fs busy
# called from cleanup_package
package_restart_daemons() {
    DebugOn package_restart_daemons

    if [ -d ${1:-/dev/null} ]; then
	e=
	for x in "$@"
	do
	    e="${e:+$e|}${x#/}"
	done
	fstat | egrep "/($e)" |
	while read user cmd pid rest
	do
	    case $pid in
	    ""|1) continue;;
	    esac
	    case $cmd in
	    cli|mgd) continue;;
	    esac
	    echo "Restarting $cmd ..."
	    kill -TERM $pid
	done
    fi
    DebugOff package_restart_daemons
}


# 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-[0-9]";;
    esac
    needclean=/tmp/.cln$$
    mounted=/tmp/.cln$$.m
    > $needclean
    > $mounted

    if isFIPSimage; 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' and '/rest-api/var'- that are important nullfs
    # mount for J-Web and rest-api services
    #
    mount | sed -n -e "/ufs,/d"			    \
		-e "/devfs,/d"			    \
		-e "/\/jail\/var/d"		    \
		-e "/\/var\/jails\/rest-api/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
        [ -d $pkgdir_mnt/$mounted_package ] || continue
        # try to unmount it
        if umount $pkgdir_mnt/$mounted_package 2>/dev/null; then
            mdconfig -d -u ${mddev##*md} >/dev/null 2>&1
	    for d in $base_pkgdir $pkgdir
	    do
		[ -f "$d/umount.$mounted_package" ] || continue    
		rm -f "$d/umount.$mounted_package"
	    done
	else
	    # communicating to the parent of a redirected
	    # loop can be a pain...
	    echo $pkgdir_mnt/$mounted_package >> $needclean
	fi
	# see if it can tell us where the pkgfile is
	for d in $base_pkgdir $pkgdir
	do
	    [ -s "$d/mount.$mounted_package" ] || continue
	    eval `grep pkgpath= $d/mount.$mounted_package; :`
	done
        pkgpath=${pkgpath:-$pkgdir/$mounted_package}
	for d in $base_pkgdir $pkgdir
	do
	    [ -f "$d/mount.$mounted_package" ] || continue
	    rm -f "$d/mount.$mounted_package"
	done
        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"
	case "$MYNAME" in
	cleanup-pkgs)
	    # This is only safe to call from cleanup-pkgs
	    # since we don't want to hose ourselves during an upgrade.
	    if [ ${loop_count:-0} -gt 20 ]; then
		# we have been trying for a while
		package_restart_daemons `cat $needclean`
	    fi
	    ;;
	esac
    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 `junos_boot_from_iso $old_package`
        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

    # on system like SRX its possible to not have the package mount point
    # so we do the following only if the mount point is available

    if [ -d $pkgdir_mnt ]; then 
	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
    fi

    )
    trace cleanup_package finished.
    DebugOff cleanup_package
}

# Check if platform should use functions which
# try to copy ISO to RAM before mounting
check_use_package_mfs_functions()
{
    product_model=${product_model:-`sysctl -n hw.product.model`}

    case "${product_model}" in
    ex*) return 0;;
    qfx*) return 0;;
    pvi*) return 0;;
    esac
    return 1
}

# 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
        if check_use_package_mfs_functions; then
            mkdir -p $pkgdir/mfs-${package}
            create_mount_package_mfs $pkgdir $package $pkgfile $mountdir > $mountpkg
            create_umount_package_mfs $pkgdir $package $pkgfile $mountdir > $umountpkg
        else
            create_mount_package $pkgdir/$pkgfile $mountdir > $mountpkg
            create_umount_package $pkgdir/$pkgfile $mountdir > $umountpkg
        fi
        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
}

# Generic place for notices that should only be displayed once
#
issue_notices () {
    local pkg_origin="$1"
    local content
    # In +REQUIRE, $instance will be INSTALL
    # During jbundle +INSTALL, PKG_JBUNDLE will be set
    case "$instance,$PKG_VALIDATING,$PKG_JBUNDLE" in
    INSTALL,,) ;;
    *) return ;;
    esac

    content=`echo $pkg_origin | sed -n 's/SDK_/&/p'`
    # Only do this for non-release builds (and not customer-built sdk packages)
    if [ -z "$content" ]; then 
        case R in
        [$pkg_supported_ltrs]) ;;
        *)
	   warn
	   warn "    The software that is being installed has limited support."
	   warn "    Run 'file show /etc/notices/unsupported.txt' for details."
	   warn
	   ;;
    	esac
    fi
    NOTICES_ISSUED=:
    export NOTICES_ISSUED
}

[ -z "$PKG_TRACE_SHELL" ] || DEBUG_SH="$DEBUG_SH,all,!make_symlinks"

#
# 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-15.1R7-S2.
    # 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=jinstall-ex-15.1R7-S2
    base_pkgdir=/packages
    pkgdir=${pkgdir:-$base_pkgdir}
    pkgdir_mnt=$base_pkgdir/mnt
    base_mountdir=$pkgdir_mnt/$package
    base_mountpkg=$pkgdir/mount.$package
    base_umountpkg=$pkgdir/umount.$package
    finish_install=$base_pkgdir/finish-install.$package
    finish_deinstall=$base_pkgdir/finish-deinstall.$package

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

    if [ -z "$PKG_BOOTSTRAP" -o "$pkgdir" != "$base_pkgdir" ]; 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
    pkg_origin=`sed -n '/^@comment.*ORIGIN:/ { s,.*ORIGIN:[[:space:]]*,,p;q; }' +CONTENTS 2> /dev/null`

    $NOTICES_ISSUED issue_notices $pkg_origin
    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_ex() {
    DebugOn platform_check_ex

    local pkgname
    local package_not_compatible
    pkgname=$1
    product_model=${product_model:-`sysctl -n hw.product.model`}
    ex_vm_mode=`sysctl -n hw.re.vm_mode 2>/dev/null`
    if [ $? -ne 0 ];then
        ex_vm_mode=0
    fi
    
    # if this is a pkgfile, get real pkg_name from +CONTENTS file    
    if [ -f "$1" ]; then
      pkgname=`tar -zxO --fast-read -f "$1" '+CONTENTS' 2>/dev/null | \
                  awk '/^@name/ { print $2; }' 2>/dev/null`
    fi

    package_not_compatible=0
    case "${pkgname}:${product_model}:${ex_vm_mode}" in
    *ex-2200:ex22*:0) ;;
    *ex-3200:ex32*:0) ;;
    *ex-3242:ex32*:0) ;;
    *ex-3242:ex42*:0) ;;
    *ex-3300:ex33*:0) ;;
    *ex-4200:ex42*:0) ;;
    *ex-4300:ex43*:0) ;;
    *ex-4500:ex45*:0) ;;
    *ex-6200:ex62*:0) ;;
    *ex-8200*:ex82*:0) ;;
    *ex-4600*:ex46*:0) ;;
    *ex-4600*img*:ex46*:1) ;;
    *ex-4600*img*:ex46*:0)
    package_not_compatible=1
    ;;
    *jinstall-vjunos*:ex46*:1) ;;
    jinstall:ex92*:0) ;;
    jinstall-ex92xx:ex92*:0) ;;
    juniper:ex92*) ;;
     *ex-8200*:olive:0) ;;
    *ex-xre200:ex-xre*:0) ;;
    *ex-*86*:olive:0) ;;
    *) Error "Cannot install $pkgname on $product_model" ;;
    esac

    if [ $package_not_compatible -eq 1 ]; then
        if [ $ex_vm_mode -eq 1 ]; then
	    echo "ERROR: Cannot install $pkgname(bare-metal image) on $product_model VM"
            Error "Use JUNOS VM package"
        else
            Error "Cannot install $pkgname on $product_model"
        fi
    fi
    DebugOff platform_check_ex
}

platform_check_qfx() {
    local pkgname
    local package_not_compatible
    pkgname=$1
    product_model=${product_model:-`sysctl -n hw.product.model`}
    qfx_vm_mode=`sysctl -n hw.re.vm_mode 2>/dev/null`
    if [ $? -ne 0 ];then
        qfx_vm_mode=0
    fi

    # if this is a pkgfile, get real pkg_name from +CONTENTS file    
    if [ -f "$1" ]; then
      pkgname=`tar -zxO --fast-read -f "$1" '+CONTENTS' 2>/dev/null | \
                  awk '/^@name/ { print $2; }' 2>/dev/null`
    fi

    package_not_compatible=0
    case "${pkgname}:${product_model}:${qfx_vm_mode}" in
    *qfx-5*img*:qfx5*:1) ;;
    *qfabric-5*img*:qfx5*:1) ;;
    *qfx-10*img*:qfx10*:1) ;;
    *qfx-5*img*:qfx5*:0)
        package_not_compatible=1
        ;;
    *qfabric-5*img*:qfx5*:0) 
        package_not_compatible=1
        ;;
    *tvp*img*:pvi*:0)
        package_not_compatible=1
        ;;
    *tvp*img*:pvi*:1) ;;
    *tvp*:pvi*:0) ;;
    *jcp*img*:pvi*:0)
        package_not_compatible=1
        ;;
    *jcp*img*:pvi*:1) ;;
    *jcp*:pvi*:0) ;;
    *jinstall-vjunos*:pvi*:1) ;;
    *tvp*img*:qfx5100-tvp:0)
        package_not_compatible=1
        ;;
    *tvp*img*:qfx5100-tvp:1) ;;
    *tvp*:qfx5100-tvp:0) ;;
    *jinstall-vjunos*:qfx5*:1) ;;
    *jinstall-vjunos*:qfx10*:1) ;;
    *qfx-5*:qfx5*:0) ;;
    *qfabric-5*:qfx5*:0) ;;
    *qfx*:qfx*:0) ;;
    *dc-re*:fx-jvre*:0) ;;
    *:dc_olive*:0) ;;
    *)
        package_not_compatible=1
        ;;
    esac

    if [ $package_not_compatible -eq 1 ]; then
        if [ $qfx_vm_mode -eq 1 ]; then
	    echo "ERROR: Cannot install $pkgname(bare-metal image) on $product_model VM"
            Error "Use JUNOS VM package"
        else
            Error "Cannot install $pkgname on $product_model"
        fi
    fi
}

# 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
    # check to accept JSR Image on Dr.Pepper Hardware
    jsr:j[1-9][0-9][0-9][0-9]:*) ;; # ok

    vjx:vjx[1-9][0-9][0-9][0-9]:*) ;; # ok
    
    jinstall_srx5000:srx5[0-9]00:*) ;; # jinstall_srx5000 on srx5*00 is ok
    srx5000:srx5[0-9]00:*) ;; # install srx5000 on srx5*00 is ok 
    srx5000:a20:*) ;;
    srx5000:a40:*) ;;
    # a20/a40 are legacy names of srx5600/srx5800, we support them // <<For backward compatability>>
    srx3000:srx3[0-9]00:*) ;; # install srx3000 on srx3*00 is ok
    srx3000:a2:*) ;;
    srx3000:a10:*) ;;
    # a2/a10 are legacy names of srx3000 platforms, we support them 
    srx1k3k:srx[1-3][0-9]00:*) ;; # install srx1k3k on srx1*00 and srx3*00 is ok
    srx1k3k:a1:*) ;;
    srx1k3k:a2:*) ;;
    srx1k3k:a10:*) ;;
    # a1/a2/a10 are legacy names of srx1k3k platforms, we support them 

    srx5000:*) # install srx5000 on other platform are not ok
	Error "Unsupported platform $product_model, use a non-srx5000 package"
	;;
    *:srx5[0-9]00:*) # install non jssg on srx5*00 is not ok
	Error "Unsupported package $1 for platform $product_model, use a srx5000 package"
        ;;
    srx3000:*) # install srx3000 on other platform are not ok
        Error "Unsupported platform $product_model, use a non-srx3000 packge"
        ;;
    *:srx3[0-9]00:*) # install non srx3000 on srx3*00 is not ok
        Error "Unsupported package $1 for platform $product_model, use a srx3000 package"
	;;
    srx1k3k:*) # install srx1k3k on other platform are not ok
        Error "Unsupported platform $product_model, use a non-srx1k3k packge"
        ;;
    *:srx[1-3][0-9]00:*) # install non srx1k3k on srk1*00 or srx3*00 is not ok
        Error "Unsupported package $1 for platform $product_model, use a srx1k3k package"
	;;
    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"
	;;

    # installing srxsme package on SRX 1xx 2xx is ok
    # allow product name to be both srx* and jsrx* to allow installation on
    # boxes which have older packages installed (product name jsrx*).
    srxsme:srx[12][0-9][0-9]*:*)
        ;;
    srxsme:jsrx[12][0-9][0-9]*:*)
        ;;

    # installing srxsme package on SRX 5xx and 6xx is ok
    srxsme:srx[5-6][0-9][0-9]:*)
        ;;
    # installing srxsme package on other platforms is not ok
    srxsme:*:*)
        Error "Unsupported platform $product_model, use a non-srxsme package"
        ;;
    # installing non-srxsme package on SRX 1xx 2xx is not ok
    *:srx[12][0-9][0-9]*:*)
        Error "Unsupported package $1 for platform $product_model, use a srxsme package"
        ;;
    # installing non-srxsme package on SRX 5xx and 6xx is not ok
    *:srx[5-6][0-9][0-9]:*)
        Error "Unsupported package $1 for platform $product_model, use a srxsme package"
        ;;

    # installing LN/ESR package on LN/ESR* is ok
    {ln|esr}:{ln|esr}*:*)
        ;;
    # installing LN/ESR package on other platforms is not ok
    {ln|esr}:*:*)
        Error "Unsupported platform $product_model, use a non-LN package"
        ;;
    # installing non-LN/ESR package on LN/ESR is not ok
    *:{ln|esr}*:*)
        Error "Unsupported package $1 for platform $product_model, use a LN package"
        ;;
     # installing any version of jweb-ex-app package for EX
    jweb-ex-app*:ex*:*)
        ;;
    # check for installing the correct EX package
    *:ex*:*)
        platform_check_ex $1
        ;;
    # check for installing the correct QFX package
    *:qfx*:*|*:fx-jvre*:*|*:dc_olive*:*|*:pvi*:*)
        platform_check_qfx $1
        ;;
    *:vrr:*) ;;
    esac
    DebugOff platform_check
}

# Surround non-numerics by space during sort so that 11.4R8 sorts
# before 11.4R10 and 11.4X25-D9.1 before 11.4X25-D10
version_max() {
    for _v in "$@"; do echo $_v; done |
	sed 's,\([^0-9.][^0-9.]*\), \1 ,g' |
	sort -n +0 -1 +1 -2 +2 -3 +3 -4 +4 -5 | tail -1 | sed 's, ,,g'
}

version_lt() {
    m=`version_max "$@"`
    test $m = $2 -a $m != $1
}

version_ge() {
    m=`version_max "$@"`
    test $m = $1
}

#
# version_check
#
# Check package against base OS.
#
version_check() {
    DebugOn version_check

    if [ -n "$PKG_VERSION_CHECK_DISABLED" ]; then
	return
    fi

    local current=`sed 's,.*\[\([1-9][0-9.]*\).*,\1,' /etc/db/pkg/junos/+COMMENT`
    local min_release=${1:-15.1}
    
    if version_lt ${current:-0.0} $min_release; 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
	*/junos-upgrade*) ;;
	*/junos-install*) ;;
	*/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}
    local filesys=${2:-/packages}
    local file=${3:-$instmp}

    if [ -z "$PKG_STORAGE_CHECK_DISABLED" ]; then
	# get space available - and where it is.
	eval `df -k $filesys | ( read h; read d s u a c o; echo available=$a on=$o )`
	suggested=`du -ks $file | ( 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;;
	    *) on=$filesys;;	
	    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
}

# system_memory_check()
# Upgradation of JUNOS 9.3 or higher versions on all
# routers require RAM greater than 256MB.
#
# Display error messages if the routers have less than or
# equal to 256 MB RAM and trying to upgrade to versions 9.3 and higher.
#
system_memory_check() {
    # For upgradation to this package(JUNOS 9.3 and above)
    # minumum recommended memory size in MB.
    recommended_memsize=512

    # Lowest threshold memory size: equal or below 256MB size is not allowed.
    min_memsize=268435456

    # calculate the system memory size
    memsize=`/sbin/sysctl -n hw.physmem 2>/dev/null`
    if [ $? -ne 0 ]; then
        warn "Unable to determine physical memory size."
        warn_abort
    fi

    # Check if RAM is less than or equal to 256 MB, if so, error and abort the installation.
    if [ $memsize -le $min_memsize ]; then
            error_more "This package can't be installed with `expr $memsize / 1024 / 1024` MB of RAM."
            error_more "For JUNOS 9.0 and higher, at least $recommended_memsize MB of RAM is recommended."
            Error "Upgrade the RAM to $recommended_memsize MB or more and try installing again."
    fi
}

sd_version_checkat_rsd() {
    # checking at RSD system.
    sd_version=2
    sysctl hw.re.sd_my_sd_version > /dev/null 2>&1 || return

    # hw.re.sd_my_sd_version is to get the SD_MSG_VERSION at current system.
    rsd=`sysctl -n hw.re.sd_my_sd_version`

    # hw.re.sd_psd_versions is used at RSD to get all PSD's versions.
    psds="`sysctl -n hw.re.sd_psd_versions`"
    loopc=0
    incomp=0
    if [ "$rsd" -a "$rsd" -ne 0 ]
    then 
        for i in $psds
        do
            if [ $i -ne 0 ]
            then 
                if [ $i -ne $sd_version ]
                then
                    warn
                    warn "PSD $loopc will not be able to communicate with RSD after this installation"
                    incomp=1
                fi
            fi    
            loopc=`expr $loopc + 1`
        done    
        if [ $incomp -eq 1 ]
        then
            warn 
            warn "The PSD's listed above will not be able to communicate with RSD after this"
            warn "installation."
            warn_abort
        fi    
    fi    
}

sd_version_checkat_psd() {
    # checking at PSD system.
    # hw.re.sd_my_sd_version is to get the SD_MSG_VERSION at current system.
    psd_version=2
    sysctl hw.re.sd_my_sd_version > /dev/null 2>&1 || return

    # hw.re.sd_rsd_version is used at PSD to get RSD version.
    rsd_version=`sysctl -n hw.re.sd_rsd_version`

    if [ "$rsd_version" -a "$rsd_version" -ne 0 ]
    then 
        if [ $psd_version -ne $rsd_version ]
        then
            warn
            warn "The new installation message version is incompatible with the version"
            warn "at RSD. PSD wont be able to communicate with RSD if you proceed."
            warn "Please contact RSD admin."
            warn_abort
        else
            inform "The new installation SD message version at PSD is compatible with the version at RSD."
            inform "This PSD's message version is $psd_version and RSD's message version is $rsd_version." 
        fi
    fi
}

sd_msg_version_check() {
    sysctl hw.re.sd_mode > /dev/null 2>&1 || return

    if [ -z "$PKG_FORCE" ]
    then
        product_model=`sysctl -n hw.product.model`
        case "$product_model" in
        t640 | t320)
            is_rsd=`sysctl -n hw.re.sd_mode`
            if [ $is_rsd -eq 2 ]
            then
                sd_version_checkat_rsd
            elif [ $is_rsd -eq 1 ]
            then
                sd_version_checkat_psd
            fi
            ;;
        *)
            ;;
        esac
    fi
}

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 $VERIEXEC_NOEXT -C $instmp $instmp/pkg/manifest
    fi
}

#
# pic combination check
#
# Certain pic combinations in a pic are not allowed
#
pic_combination_check() {
    unpack_pkgtools
    if [ -x $instmp/bin/checkpic ]; then
	$instmp/bin/checkpic || dire_warn -r pic
    fi
}

#
# product_is_vmx()
# returns true if product is vmx
# else false
#
product_is_vmx() {
    if [ "$(sysctl -n hw.re.model)" = "VMX" ]; then
        true
    else
        false
    fi
}

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

    if product_is_vmx && [ "$1" = "jpfe" ]; then
        return
    fi
    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: "$@"

    # deal with simple [in]equality
    case "$2" in
    -ne|!=|-eq|=)
	case "$2" in
	-ne) _op="!=";;
	-eq) _op="=";;
	*) _op="$2";;
	esac
	test "$1" "$_op" "$3" > /dev/null
	return $?
	;;
    esac

    # more complex checks
    m=`version_max "$1" "$3"`
    case "$2" in
    -gt|\>) test $m = $1 -a $m != $3;;
    -lt|\<) test $m = $3 -a $m != $1;;
    -ge|\>=|=\>) test $m = $1;;
    -le|\<=|=\<) test $m = $3;;
    *) test "$@" > /dev/null;;
    esac
}


#
# 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 product_is_vmx && [ "$1" = "jpfe" ]; then
        false
    elif [ -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
}

# make minimal assumptions
other_get_pid() {
    if [ -r /var/run/$1.pid ]; then
        cat /var/run/$1.pid
    else
	ps axc | sed -n "/ $1\$/ { s,^ *,,;s, .*,,p; }"
    fi
}

daemon_send_signal()
{
    if [ -z "$PKG_BOOTSTRAP" ] ; then
	local daemon_pid=`daemon_get_pid "$2"`
	daemon_pid=${daemon_pid:-`other_get_pid "$2"`}
	if [ ! -z "$daemon_pid" ]; then
	    kill -$1 "$daemon_pid"
	fi
    fi
}

daemon_restart_other() {
    case $1 in
    *${HasKillDaemons}*)
	;;
    *)
	echo "Restarting $1 ####..."
	;;
    esac
    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=2		# unavailable(ENOENT)
    fi
    if [ $rc = 2 ]; then
        daemon_send_signal TERM "$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() {
    local platform_has_jkernel
    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

    product_model=${product_model:-`sysctl -n hw.product.model`}
    case "${product_model}" in
      ex*) platform_has_jkernel=no ;;
      qfx*|pvi*) platform_has_jkernel=no ;;
      *) platform_has_jkernel=yes ;;
    esac

    # XXX: The following check was added in SVN revision 28992 by abstine.
    # This was around the time that the first jkernel package was
    # implemented.  Previous versions didn't have the kernel in a package.
    # This check was meant to handle the case when someone was upgrading the system
    # from a JUNOS version where the kernel wasn't in a jkernel package,
    # to a JUNOS version where the jkernel package was present.
    # This check can probably be deleted at some point, since jinstall has had
    # a jkernel package for many years now.  Newer platforms like EX and QFX
    # do not have a jkernel package, so this check fails on those platforms.
    if [ "$platform_has_jkernel" = "yes" ]; then
        # 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
    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 jkernel-ex ; then
	if [ -z "$jkernel_ex_works" ]; then
	    dot_file jkernel_ex quietly
	fi
	if [ ! -z "$jkernel_ex_works" ]; then
	    if jkernel_ex_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 jbase-ex ; then
        if [ -z "$jkernel_ex_works" ]; then
            dot_file jkernel_ex quietly
        fi
        if [ ! -z "$jkernel_ex_works" ]; then
            if jkernel_ex_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 jroute-ex ; then
        if [ -z "$jroute-ex_works" ]; then
            dot_file jroute-ex quietly
        fi
        if [ ! -z "$jroute_ex_works" ]; then
            if jroute_ex_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 package_exists jmobile ; then
	if [ -z "$jmobile_works" ]; then
	    dot_file jmobile quietly
	fi
	if [ ! -z "$jmobile_works" ]; then
	    if jmobile_needs_to_reboot ; then
		need_to_reboot_rc=true
	    fi
	fi
    fi

    if package_exists jmacsec ; then
	if [ -z "$macsec_works" ]; then
	    dot_file jmacsec quietly
	fi
	if [ ! -z "$jmacsec_works" ]; then
	    if jmacsec_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
    local allow_restart_mgd
    trace restart_mgd

    if [ "$package" = jroute -o -d $pkg_db_dir/jroute -o -z "$PKG_IS_JUNOS" ] ; then
        allow_restart_mgd=yes
    else
        product_model=${product_model:-`sysctl -n hw.product.model`}
        case "$product_model" in
        ex*) allow_restart_mgd=yes ;;
          *) trace no jroute package; return ;;
        esac
    fi


    [ -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."
            if ${SafeModeCommit:-false} ; then
                #
                # We sometimes need mgd to commit the existing configuration
                # even if it has some errors. Particularly for situations
                # of upgrade/downgrade of subset packages with their own
                # configurations.  This, in concert with having to restart
                # daemons like fwdd/flowd can cause the system to become
                # unreachable (interfaces don't get initialized) unless
                # other parts of valid configurations are allowed to occur.
                #
                # Here, we expect mgd to commit configurations that are
                # valid, ignore blocks for which the schema does not exist,
                # and rely on daemons to handle linkages carefully.  (for
                # example, fwdd/flowd will silently ignore app-accel
                # directives if that package has been removed).
                #
                warn "Activating Partial Configuration in $config_file.  Correct as needed"
                $mgd -I -ZO -Zs
            else
	        warn "Correct the errors and commit the configuration."
	        rc=true
            fi
	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_other_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
}

check_copy_iso_to_mfs()
{
    local physmem
    local min_memsize

    # If hw.physmem is less than approximately 1G,
    # do not copy ISO to MFS
    min_memsize=900000000

    physmem=`sysctl -n hw.physmem 2> /dev/null`
    if [ ${physmem} -lt ${min_memsize} ]; then
	return 1
    fi
    return 0
}

#
# 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_mount_package_mfs
#   Create script to mount specified package.
#   Package may be copied to mfs, if enough RAM is available.
#
# args
# $1  - package-path to mount
# $2  - package
# $3  - package file
# $4  - mount point for package
create_mount_package_mfs () {
    DebugOn create_mount_package_mfs
    local pkgpath mountpoint
    local do_copy_iso_to_mfs
    local mfs_path
    local min_buf_size 
    local buf_size 
 
    pkgpath=$1
    mountpoint=$4

    if check_copy_iso_to_mfs; then
	mfs_path=mfs-${package}
    else
	mfs_path=
    fi

    # 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
if [ ! -s $pkgpath/$pkgfile ]; then
    pkgdir=`dirname $pkgpath/$pkgfile`
    # 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

mfs_path=${mfs_path}
if [ -n "\${mfs_path}" ]; then
    pkg_size=\`ls -l $pkgpath/$pkgfile | awk '{print \$5}'\`
    # the minimum buffer size allocated for an md in mfs is 5MB.
    # if the package size is large, we allocate 15% of package size as buffer
    min_buf_size=\$((5*1024*1024))
    buf_size=\$(((15*\${pkg_size})/100))
    if [ \$buf_size -le \$min_buf_size ]; then
        buf_size=\$min_buf_size
    fi
    mfs_size=\$((\${pkg_size} + \${buf_size}))
    mdmfs -S -s \${mfs_size}b md $pkgpath/mfs-${package}
    cp ${pkgpath}/${pkgfile}* ${pkgpath}/mfs-${package}/
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 $pkgpath/\${mfs_path}/$pkgfile $mountpoint $package"
    
    DebugOff create_mount_package_mfs
}

#
# Create script to unmount specified package
#
# $1  - package-path to mount
# $2  - package
# $3  - package file
# $4  - mount point for package
create_umount_package_mfs () {
    DebugOn create_umount_package_mfs
    local pkgpath mountpoint
    local do_copy_iso_to_mfs
    local mfs_path

    pkgpath=$1
    mountpoint=$4

    if [ ! -x /sbin/umount_iso ]; then
	error "Cannot find /sbin/umount_iso!"
    fi

    if check_copy_iso_to_mfs; then
	mfs_path=mfs-${package}
    else
	mfs_path=
    fi

    echo "exec /sbin/umount_iso $pkgpath/${mfs_path}/$pkgfile $mountpoint $package"

    DebugOff create_umount_package_mfs
}

#
# 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 $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_bin_compatibility
#
# Check that the given package api's is compatible on this system.
#

check_bin_compatibility()
{
    if [ "%PKG_UNIX_SDK_API_VERSION%" != "918010" ]; then
	error "Packages API Version: %PKG_UNIX_SDK_API_VERSION% does not match Junos API version: 918010"
    fi
}

#
# Component package / add-on package should just check for
# architecture compatibility between kernel and the package.
# Machine compatibility check is applicable only for jinstall.
#
check_kern_arch_compatibility()
{
    kernel_compat_list=`uname -m`
    case " $kernel_compat_list " in
    *" arm "*) ;;
    *) Error "Package $1 is not kernel compatible - arm vs $kernel_compat_list"
    esac
}

check_arch_compatibility()
{
    re_name=`/sbin/sysctl -n hw.re.name 2>/dev/null`
    if [ -z "$re_name" ]; then
        Error "hw.re.name sysctl not supported."
    fi

    case "$re_name" in
    RE-S-1800x2|RE-S-1800x4|RE-A-1800x2|RE-TXP-LCC|RE-DUO-1800|RE-DUO-1800-16G|RE-DUO-2600|RE-JCS1200-1x2330|Olive|RE-JCS1200-1x2400|RE-S-EX9200-1800X4|RE-VRR|RE-VMX)
        machine_compat_list="i386 amd64"
        ;;
     *)
        machine_compat_list=`/sbin/sysctl -n hw.machine_arch 2>/dev/null`
        machine_compat_list=${machine_compat_list:-`uname -m`}
        if [ -z "$machine_compat_list" ]; then
            Error "machine architecture unknown."
        fi
        ;;
    esac

    case " $machine_compat_list " in
    *" arm "*) ;;
    *) Error "Package $1 is not compatible - arm vs {$machine_compat_list}"
    esac
}

check_cores_access()
{
    # Take parameters from jinstall-ex-header
    # access and sharing mask for CPU cores: 
    # 1=ctrl 2=data 4=user
    pkg_cores_access=${cores_access:-0}
    pkg_cores_sharing=${cores_sharing:-7}

    # Default cores access and sharing
    tot_cores_access=0
    tot_cores_sharing=7
 
    # Remove traces of our own, if exist
    if [ -r $opt_pkgdir/jinstall-ex.access ]; then 
        echo "Removing old $opt_pkgdir/jinstall-ex.access"
        rm $opt_pkgdir/jinstall-ex.access
    fi


    # Include other packages cores access file
    # to summarize total cores access and sharing
    for f in $opt_pkgdir/*.access; do
        if [ -r $f ]; then 
            . $f
            tot_cores_access=$((tot_cores_access | cores_access));
            tot_cores_sharing=$((tot_cores_sharing & cores_sharing));
        fi
    done

    # Check for sharing violation
    if [ $tot_cores_access -ne 0 ]; then
        if  [ $((tot_cores_access & pkg_cores_sharing)) -eq 0 ]; then
            echo "Package jinstall-ex can not be installed: sharing violation."
            echo "    jinstall-ex cores sharing mask is $pkg_cores_sharing"
            echo "    Other packages cumulative access mask is $pkg_cores_sharing"
            return 13; # EACCESS
        fi
    fi

    if [ $pkg_cores_access -ne 0 ]; then
        if [ $((tot_cores_sharing & pkg_cores_access)) -eq 0 ]; then
            echo "Package jinstall-ex can not be installed: sharing violation."
            echo "    jinstall-ex cores access mask is $pkg_cores_access"
            echo "    Other package's cumulative cores sharing mask is $tot_cores_sharing"
            return 13; # EACCESS
        fi
    fi

    # Record cores access and sharing for this package
    mkdir -p $opt_pkgdir
    cat << EOF > $opt_pkgdir/jinstall-ex.access
cores_access=$pkg_cores_access
cores_sharing=$pkg_cores_sharing
EOF
    
    return 0
}

#
# selective_update_version_check
#
# Check selective-update package against given package
# Also check whole version if 'strict' paramater is given (#3 param)
#
# Param:
# $1 = Package name whose version needs to be checked.
# $2 = Version string
# $3 = 'strict' i.e. check whole version or Major version only.
#
selective_update_version_check() {
    local pkg=$1
    local ver=$2
    local strict_version_check=$3

    if [ ! -d /etc/db/pkg/$pkg ]; then
	echo "ERROR: Package '$pkg' is not installed."
    elif [ "$strict_version_check" = "strict" ]; then
	local current=`sed -e 's,.*\[\(.*\)\],\1,' /etc/db/pkg/$pkg/+COMMENT`
	if [ "$current" = "$ver" ]; then
	    return 0
	fi
    else
	local current=`sed -e 's,.*\[\(.*\)\],\1,' /etc/db/pkg/$pkg/+COMMENT`
	case $current in
	$ver*) return 0;;
	esac
    fi

    echo "Package jinstall-ex can not be installed: Incompatible version - $current:$ver";

    return 1
}

#
# selective_update_need_reboot
#
# Fail selective-update package installation if reboot is needed
#
selective_update_needs_reboot() {
    local issu

    # Do not check for 'reboot' option if this is in validation phase.
    [ -n "$PKG_VALIDATING" ] && return 0;

    if [ -z "$PKG_USER_WILL_REBOOT" -a -z "$NO_AUTO_REBOOT" ]; then
	issu=`sysctl -n hw.re.issu_state`
	issu=${issu:-0}
	#
	# issu state
	#        0 => NO ISSU
	#        1 => ISSU ERROR
	#    >=480 => ISSU UNKNOWN/UNDEFINED
	#
	# Display error/warning only if RE is not in ISSU state.
	# ISSU will anyway rebot the RE.
	#
	if [ $issu -eq 0 -o $issu -eq 1 -o $issu -ge 480  ]; then
	    warn
	    warn "    This pkg needs reboot option. Use the 'reboot' option"
	    warn "    to proceed."
	    warn
	    return 1
	fi
    fi

    return 0
}

# We use /usr/libexec/ui/package-info to get junos-version if it exists
set_junos_release_vars() {
    if [ -x /usr/libexec/ui/package-info ]; then
	junos_release_tag=`/usr/libexec/ui/package-info -X | sed -n '/junos-version/{s,.*>\(.*\)</.*,\1,p;q;}'`
    else
	junos_release_tag=`sed 's,\(.*\)\(\[\)\(.*\)\(\]\),\3,' /etc/db/pkg/junos/+COMMENT 2> /dev/null`
    fi
    junos_release=`echo $junos_release_tag | sed "s,.*\([1-9][0-9].[0-9][$pkg_supported_ltrs][0-9]*\).*,\1,"`
    junos_release_category=`echo $junos_release | sed "s,.*\([1-9][0-9].[0-9]\)\([$pkg_supported_ltrs|I]\).*,\2,"`
}

strict_junos_version_match() {
    set_junos_release_vars
    test x$junos_release_tag != "x${1:-15.1R7-S2}"
}

# Check whether JVAS release and base Junos release match.
# Release is defined as '<major>.<minor><category><build>', e.g. 12.1R2
# Junos release tag may look like:
#   <release>[.<spin>] or <release>[-<type>[.<spec>]], e.g. 12.1B1-PS.1
# JVAS release tag may look like:
#   <release>[.<spin>]-<jvas-spin>[-A<appmajor>.<appminor>], e.g. 12.1R2.9-3-A1.2
check_jvas_version () {
    set_junos_release_vars
    jvas_release_tag=15.1R7-S2
    jvas_release=`echo $jvas_release_tag | sed "s,.*\([1-9][0-9].[0-9][$pkg_supported_ltrs][0-9]*\).*,\1,"`
    jvas_release_category=R

    msg_line1="Software package '$package' has version [$jvas_release]."
    msg_line2="This version has not been qualified to work"
    msg_line3="with the installed version of Junos [$junos_release]."
    msg_line4="Juniper cannot guarantee the software package/Junos will work as intended."
    msg_line5="ANY FURTHER USE OF THIS UNSUPPORTED SOFTWARE BUILD"
    msg_line6="IS ENTIRELY WITHOUT JUNIPER LICENSE OR CONSENT"
    msg_line7="AND IS ENTIRELY AT THE USER'S RISK."

    case $junos_release_category,$jvas_release_category in
    [$pkg_supported_ltrs],[$pkg_supported_ltrs]) pkg_supported=yes ;;
    *);;
    esac

    if [ "$junos_release" != "$jvas_release" ]; then
        if [ "$pkg_supported" -a -z "$PKG_FORCE" ]; then
            error_more
            error_more $msg_line1
            error_more $msg_line2
            error_more $msg_line3
            Error
        else
            logger logger -p daemon.warning "$msg_line1 $msg_line2 $msg_line3"
            warn
            warn $msg_line1
            warn $msg_line2
            warn $msg_line3 
            warn
            warn $msg_line4
            warn $msg_line5
            warn $msg_line6
            warn $msg_line7
            warn
        fi
    fi
}

#
# The symbolic link will be deleted if jinstall-ex owns the link.
# Return TRUE (0) in that case. Otherwise return FALSE (1).
#
jsu_is_mine()
{
    if [ ! -f "$1" ]; then
	return 0
    else
	return 1
    fi
}

#
# jsu_reset_symlink <preferrred_pkg> <fallback_pkg> <file>
#
jsu_reset_symlink()
{
    local tfile=/tmp/.tfile
    local tgt_pkg=$1
    local def_pkg=$2
    shift 2

    if ! jsu_is_mine $1; then
	return 1
    fi

    sed_pattern="$sed_pattern -e 's, /*$1$,&,p'"
    if [ -n "$sed_pattern" ]; then
	if [ "$tgt_pkg" = "no-pname" ]; then
	    tgt_pkg="$def_pkg"
	else
	    if [ ! -s $pkgdir/$tgt_pkg.symlinks ]; then
		tgt_pkg=$def_pkg
	    fi
	fi
	symlink_file=$pkgdir/$tgt_pkg.symlinks
	if [ ! -s $symlink_file ]; then
	    Error "Could not reset link to '$tgt_pkg'"
	fi
	eval sed -n $sed_pattern $symlink_file >$tfile
	make_symlinks $tfile
	/bin/rm $tfile
	return 0
    fi
    return 1
}

# virtual_chassis_configuration_check()
# Upgradation of JUNOS 14.1X53-D40 or higher versions on all
# VC/VCF switches require validation of virtual chassis configuration.
#
# Display error messages if the switch has more than two routing
# engines in configuration.
#
virtual_chassis_configuration_check()
{
    vc_enable=`sysctl -n hw.vc.enabled`

    if [ $vc_enable -eq 1 ]; then
        num_of_re=`cli -c "show configuration virtual-chassis| display inheritance| display set|match routing-engine" | wc | awk ' { print $1 }'`
        if [ 2 -lt $num_of_re ]; then
            error_more "$num_of_re routing engines are found in virtual-chassis configuration"
            Error "Please configure maximum of 2 routing engines and try again."
        fi
    fi
}

#
# This function will be called by JSU packages during 'delete'
# operation. JSU calls this function to set links of given
# files back to given/original package.
#
# jsu_reset_symlinks <preferrred_pkg>,<fallback_pkg>,<product> <file>
#
jsu_reset_symlinks()
{
    local file=$2

    case "$1" in
    auto-backup)
	mname=$package
	if [ ! -h $DESTDIR/${file%/*}/.${file##*/}.$mname ]; then
	    f=`ls -l $DESTDIR/$file | sed 's,.*-> ,,'`
	    ln -sf $f $DESTDIR/${file%/*}/.${file##*/}.$mname
	fi
	return $?
	;;
    esac

    f=`read_link $DESTDIR/$file`
    case $f in
    */$PKG_BASENAME/*) ;;
    *) return 1;;
    esac

    case "$1" in
    auto-restore)
	mname=$package
	ref_file=$DESTDIR/${file%/*}/.${file##*/}.$mname
	if [ -h ${ref_file} ]; then
	    f=`ls -l $DESTDIR/${ref_file} | sed 's,.*-> ,,'`
	    /bin/rm -f ${ref_file}
	    ln -sf $f ${file}
	    return 0
	else
	    echo "ERROR: File ${ref_file} not found for auto-restore"
	    return 1
	fi
	;;
    esac

    local pkginfo=$1
    shift 2

    # No auto-backup / auto-restore approach
    (
	IFS=^
	for pinfo in $pkginfo; do
	    echo $pinfo
	done
    ) |
    while read pinfo; do
	set -- `echo $pinfo | sed 's/,/ /g'`
	tgt_pkg=$1
	def_pkg=$2
	shift 2
	if [ -z "$1" ]; then
	    found=1
	else
	    while [ -n "$1" ]; do
		case $(sysctl -n hw.product.model) in
		$1) found=1; break;;
		esac
		case "$(sysctl -n hw.product.model|sed 's/-model//'):$(sysctl -n hw.product.pvi_model)" in
		$1) found=1; break
		esac
		shift
	    done
	fi
	case ${found:-0} in
	0) continue;;
	1) if jsu_reset_symlink $tgt_pkg $def_pkg $file; then
	      return 2
	   fi
	   ;;
	esac
    done
    [ $? -eq 2 ] && { return 0; } || { return 1; }
}

restart_lr_rpds() 
{ 
    for lr in `cli -c "show route summary logical-system all | except default" | awk '/logical-system/{print $NF}'`; do 
        echo "Restarting logical-system $lr" >&2 
        cli -c "restart routing logical-system $lr" >&2 
    done 
}
fi # Close the 'if' from the top of the file (PKG_SETUP_VARIABLES_ONLY)
#!/bin/sh
#
# $Id: script-funcs,v 1.21.78.1 2009-09-16 12:45:12 jyan Exp $
#
# Copyright (c) 1999-2013, Juniper Networks, Inc.
# All rights reserved.
#

# if /etc/rc.fips, then we are always FIPS
# even if fips_level has not yet been raised.
isFIPSimage() {
    test -s /etc/rc.fips
}

isFIPS() {
    isFIPSimage && return 0
    test -x /sbin/fips-mode || return 1
    /sbin/fips-mode
}

# return true if veriexec is being enforced
VERIEXEC_NOEXT=-onoext
veriexec_check() {
    rc=1
    if [ -x /sbin/veriexec ]; then
	(/sbin/veriexec -i enforce) > /dev/null 2>&1
	rc=$?
	if [ $rc = 0 -a -n "$VERIEXEC_NOEXT" ]; then
	    # do we support -onoext ?
	    (/sbin/veriexec $VERIEXEC_NOEXT -i enforce) > /dev/null 2>&1 ||
		VERIEXEC_NOEXT=
	fi
    fi
    return $rc
}

#
# 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
#
# XXX don't add sha256 yet, we only use this to find
# the files that need verifying and .sha1 will do.
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
Myname=${Myname:-${0##*/}}

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
	local rc1=1

	case "$-,$1" in
	*,-e) shift;;		# caller ok with return 1
	*e*,*) rc1=0;;		# be happy!
	esac
	case "${DEBUG_SH:-$DEBUG}" in
	"") return $rc1;;
	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 $rc1
}

# 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
}

_TTY=${_TTY:-`test -t 0 && tty`}; export _TTY

# override this if you like
_debugShell() {
	{
		echo DebugShell "$@"
		echo "Type 'exit' to continue..."
	} > $_TTY
	${DEBUG_SHELL:-${SHELL:-/bin/sh}} < $_TTY > $_TTY 2>&1
}

# Run an interactive shell if appropriate
# Note: you can use $DEBUG_SKIP DebugShell ... to skip unless debugOn
DebugShell() {
	case "$_TTY^${DEBUG_INTERACTIVE}" in
	*^|^*) return 0;;	# no tty or no spec
	esac
	for _e in ${*:-$Myname} all
	do
		case ",${DEBUG_INTERACTIVE}," in
		*,!$_e,*|*,!$Myname:$_e,*)
			return 0
			;;
		*,$_e,*|*,$Myname:$_e,*)
			# Provide clues as to why/where
			_debugShell "$_e: $@"
			return $?
			;;
		esac
	done
	return 0
}

# 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.
add_hooks() {
    eval __h="\$$1"			# current hook values
    __hook=$1  shift			# get hook name
    eval $__hook="'$__h $@'"		# append new values
}

run_hooks() {
    eval __h="\$$1"
    for e in $__h
    do
        $e
    done
}

# read_link <arg>
#
# If <arg> is not a symlink, echo <arg>.
# If <arg> is a symlink, resolve <arg>, strip out the directory path,
# and echo the file name portion of the resolved symlink.
read_link() {
    if [ -h $1 ]; then
        /bin/ls -l $1 | sed -e 's,.*-> ,,' -e 's,.*/,,'
    else
        echo $1
    fi
}

# read_link2 <arg>
#
# If <arg> is not a symlink, echo <arg>.
# If <arg> is a symlink, resolve <arg>, and echo the resolved symlink.
# Do not strip out the directory path before echoing the resolved symlink.
read_link2() {
    if [ -h $1 ]; then
        /bin/ls -l $1 | sed -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
	
	# Create provider-prefix specific directories for external RE packages
	if [ "$PKG_PROVIDER_NAME" -a "$pkg_origin" = "SDK_PKG_RE" ]; then
	    mkdir -p -m 775 /var/log/ext/$PKG_PROVIDER_NAME
	    mkdir -p -m 775 /var/run/ext/$PKG_PROVIDER_NAME
	    mkdir -p -m 775 /var/db/ext/$PKG_PROVIDER_NAME
	fi

        # make sure that the ones that should be there, are.
        while read src target flags
	do
	    # Modify path to symlinks for external RE/VE packages
	    if [ "$PKG_PROVIDER_NAME" ]; then  
		if [ "$pkg_origin" = "SDK_PKG_RE" ]; then
		    if [ "$CHECK_SYMLINKS" ]; then
			sdk_check_symlinks $target || exit $?
		    fi
		    case "$target" in
			"/opt/lib/dd/lib"*"-dd.so" | \
			"/opt/lib/dd/"*".dml" | \
			"/opt/lib/render/lib"*"-render.so" | \
		        "/var/db/scripts/op/"* | \
		        "/var/db/scripts/event/"* | \
		        "/var/db/scripts/commit/"* | \
		        "/opt/sdk/$PKG_PROVIDER_NAME/"*)
			    if [ -e "$target" ]; then
			        warn "COLLISION DETECTED"
			        warn "Link $target already exists"
			    else
			        make_symlink $src $target
			    fi;;
		        *)  error_more "$target is not within /opt/sdk/$PKG_PROVIDER_NAME"
			    [ "$PKG_FORCE" ] || break
			    if [ -e "$target" ]; then
			        warn "COLLISION DETECTED"
			        warn "Link $target already exists"
			    else
			        make_symlink $src $target
			    fi;;
		    esac
	        else
		    make_symlink $src $target
	        fi
	    else
		make_symlink $src $target
	    fi
        done < $symlinks
	
	# If src and target are set, then we aborted the symlink creation, so
	# we need to remove any links that we already created.
	if [ "$src" -a "$target" ]; then
	    while read brokensrc brokentarget flags
	    do
		# Once we reach the same src and target lines in the symlink
		# file, we are at the point of the collision and can stop.
		[ "$src" = "$brokensrc" -a "$target" = "$brokentarget" ] && break
		rm -f $brokentarget
	    done < $symlinks
	    Exit 1
	fi
    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
}

# similar to atexit but only on error.
on_error_cmds=:
on_error() {
    on_error_cmds="$*;$on_error_cmds"
}

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

# like error - but we don't allow PKG_FORCE to keep us from dying
Error() {
    error_more "$@"
    eval "$on_error_cmds"
    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
}

check_expiry() {
    local provider_name="jnxProviderName"

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

get_cert_type() {
    local cert_type="jnxCertificateType"

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

get_dep_type() {
    local dep_type="jnxDeploymentType"

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

check_allowed_extensions() {
    local extensions_allow="/var/etc/extensions.allow"

    # Figure out the provider name of the signer cert
    PKG_PROVIDER_NAME=`get_provider $certs`
    export PKG_PROVIDER_NAME
    
    # Figure out the certificate type and deployment type of the cert
    PKG_CERT_TYPE=`get_cert_type $certs`
    PKG_DEP_TYPE=`get_dep_type $certs`

    if [ "$PKG_PROVIDER_NAME" ]; then
	# Check if the SDK certificate is expired
	check_expiry $certs

	# it better be in extensions.allow
	egrep "^$PKG_PROVIDER_NAME([[:space:]].*)?\$" $extensions_allow 2>/dev/null | \
	while read provider certtype deptype
	do
	    if [ ! "$PKG_CERT_TYPE" -a ! "$PKG_DEP_TYPE" -a ! "$certtype" -a ! "$deptype" -a "$PKG_PROVIDER_NAME" = "$provider" ]; then
		exit 1 # Allow packages signed with old cert to install
	    fi

	    if [ "$PKG_PROVIDER_NAME" = "$provider" -a "$PKG_CERT_TYPE" = "$certtype" -a "$PKG_DEP_TYPE" = "$deptype" ]; then
		exit 1 # Allow packages signed with new cert to install
	    fi

	    if [ "$PKG_CERT_TYPE" != "$certtype" ]; then
		echo "Please check system extensions, license-type configuration for correctness"
	    fi

	    if [ "$PKG_DEP_TYPE" != "$deptype" ]; then
		echo "Please check system extensions, deployment-scope configuration for correctness"
	    fi

	done

	if [ $? -ne 1 ]; then
	    Error "Packages from $PKG_PROVIDER_NAME are not allowed"
	fi
    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
	    ;;
	*sha256) hash_cmd=/sbin/sha256
	    hash_ext=sha256
	    hash_name=SHA256
	    ;;
	esac

	if [ -x $hash_cmd ]; then
	    case "$hash" in
	    *sig)
		dir=`dirname $hash`
		case "$hash" in
		*esig) base=`basename $hash .esig`
			certs=`Exists $dir/$base.ecerts $dir/ecerts.pem` ;;
		*sig) base=`basename $hash .sig`
			certs=`Exists $dir/$base.certs $dir/certs.pem` ;;
		esac
		$hash_cmd -b -c $certs $hash || Exit 1
		
		# Allow/disallow external packages
		check_allowed_extensions

		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
	*.sha256|*.sha1|*.md5|*.esig|*.sig)
	    verify_hash $f
	    ;;
	*)  # try in our order of preference
	    for h in $f.esig $f.sig $f.sha256 $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} ]
}

#
# hup_daemon <daemon-name> <daemon-pid-file>
#
# send a hup signal to a daemon
#
hup_daemon() {
    if [ -s $2 ]; then
	kill -HUP `cat $2 2>/dev/null`
    elif [ -s /var/run/$1.pid ]; then
	kill -HUP `cat /var/run/$1.pid 2>/dev/null`
    else
	daemon_pid=`ps gax | grep "/$1 -N" | grep -v grep \
		    | awk '{ print \$1 }' 2>/dev/null`
	if [ ! -z "$daemon_pid" ]; then
	    kill -HUP "$daemon_pid 2>/dev/null"
	fi
    fi
    if [ $? != 0 ]; then
	error "Could not send HUP to $1"
    fi	
}

save_loader_tweaks() {
    tmpfile=/tmp/loader.tweaks$$
    # if loader.tweaks exists, prefer that over changes to loader.conf
    local product_model=`sysctl -n hw.product.model`
    [ -s /boot/loader.tweaks -a "$product_model" != "vjx1000" ] && return
    if [ -s /boot/loader.conf ]; then
        cat /boot/loader.conf | egrep -e "(ata|cid|retype|serialid|model${1:+|$1})"
    fi > $tmpfile
    [ -s $tmpfile ] && mv $tmpfile /boot/loader.tweaks
    rm -f $tmpfile
}

ve_print_msg() {
    local pkg_type pkg_size
    local file b

    b=`basename "$1" .tgz`
    file=`Exists /tmp/.pkg*.toc.$b`
    [ ! -s "$file" ] && return
    
    if [ `grep -c +junos-package.xml $file` = 1 ]; then
	pkg_type=`tar -zxO --fast-read -f $1 +junos-package.xml | \
	sed -n '/<type>/s,.*<type>\([^<]*\)</type>.*,\1,p' 2>/dev/null`
    else
	return
    fi

    case "$pkg_type" in
    SDK_PKG_VE) pkg_size=`du -h $1 | awk '{ print $1 }'`
		echo "$2 package '$1' : size ${pkg_size}B ..."
		echo -n "Depending on platform and package size above "
		echo "operation will take few seconds to several minutes ..."
		;;
    *) ;;
    esac
}

restore_loader_tweaks() {
    if [ -s /boot/loader.tweaks ]; then
        cat /boot/loader.tweaks >> /boot/loader.conf
    fi
}

printf() {
    local fmt

    fmt=`echo "$1" | sed 's/"/\\\\"/g'`
    shift

    eval "awk 'BEGIN { printf(\"$fmt\"`echo $@ | awk '{ for (i = 1; i <= NF; i++) { gsub(/\042/, "\134\042", $i); printf(", \042%s\042", $i); } }'`); }'"
}

# BIOS check 
# 
# BIOS on platforms like SRX branch needs BIOS upgrade to be transparent to 
# the user. This function checks available and installed version of BIOS to 
# decide whether BIOS needs to be upgraded automatically
#
# $1: Directory where BIOS files for installation are present
bios_check() {
    DebugOn bios_check

    # Check if BIOS auto upgrade is enabled based on output of 
    # sysctl variable hw.re.bios_auto_upgrade. If output is
    #     0: Auto upgrade is disabled. Exit
    #     1: Auto upgrade is enabled. Continue
    #     Nothing: Default is to auto upgrade. Continue
    local check_enabled=`sysctl -n hw.re.bios_auto_upgrade 2> /dev/null`
    check_enabled=${check_enabled:-1}
    if [ $check_enabled = 0 ]; then
        return
    fi

    local product_model=`sysctl -n hw.product.model`

    case "$product_model" in
    srx[12][0-9][0-9][bh-]*|srx6[0-9][0-9])

        local boot_dir=${1:-$CF/boot}

        if [ ! -d $boot_dir ]; then
            error BIOS check: Boot directory $boot_dir does not exist
            return
        fi

        # Get the product family e.g. family for product model
        # srx210h-poe is srx210
        # Also, note that older JUNOS releases had the name 
        # convention as srx210-hm for srx210 high memory. As, 
        # it is possible that we are upgrading from an older 
        # JUNOS which returns names with this convention as a 
        # result of sysctl command above, take care of that
        local product_family="${product_model%%[bh-]*}"

        # Get the mandatory BIOS version needed for product family for the 
        # Junos installed
        local mandatory_version=`awk -v PRODUCT=$product_family '$1 == PRODUCT { print $2 }' \
                                 $boot_dir/bios-autoupgrade.conf`

        # Get the version of the BIOS available for install
        # BIOS version is located at 0x500 offset in u-boot binary 
        local avail_version=`dd if=$boot_dir/uboot bs=1 iseek=0x500 count=16 2> /dev/null | \
                             sed -n '/^[0-9]*\.[0-9]*/s/\([0-9]*\)\.\([0-9]*\).*/\1\.\2/p'`

        # Get the version of the current BIOS installed on the system
        local installed_version="$(sysctl -n hw.re.biosversion)"

        # Older BIOS had a different versioning scheme which had
        # U-boot's GNU version number (1.1.6) as the version number
        # This was superseded by a SRX branch platform specific 
        # 2 digit versioning scheme for better control over code changes
        #
        # Hence, treat original version number 1.1.6 in older U-boots
        # as version 0.0
        case "$installed_version" in
        *1.1.6*)
            installed_version=0.0
        esac

        installed_version=${installed_version:-0.0}
        mandatory_version=${mandatory_version:-0.0}
        avail_version=${avail_version:-0.0}

        # If installed version is less than mandatory version,
        #        upgrade to available BIOS version
        if version_lt "$installed_version" "$mandatory_version"; then

            echo JUNOS requires BIOS version upgrade from \
                 $installed_version to $avail_version
            echo Upgrading to BIOS $avail_version ...
 
            case "$product_family" in
            srx240|srx650)

                # PR 495910 - It is possible that the variables are incorrect for
                # BIOS version < 1.5 on SRX650
                if [ $product_family = "srx650" ]; then
                    kenv boot.upgrade.uboot=0xBF400000
                    kenv boot.upgrade.loader=0xBF600000
                elif [ $product_family = "srx240" ]; then
                    # PR 554283- It is possible that the variables are incorrect for
                    # BIOS version < 1.5 on Asgard platforms 
                    kenv boot.upgrade.uboot=0xbfc00000
                    kenv boot.upgrade.loader=0xbfe00000
                fi

                # Upgrade U-boot, Loader and U-shell
                bootupgrade -u $boot_dir/uboot -l $boot_dir/loader -U $boot_dir/ushell
                ;;
            srx100|srx210)
                    # PR 554283- It is possible that the variables are incorrect for
                    # BIOS version < 1.5 on Asgard platforms 
                    kenv boot.upgrade.uboot=0xbfc00000
                    kenv boot.upgrade.loader=0xbfe00000

                    # Upgrade U-boot and Loader
                    bootupgrade -u $boot_dir/uboot -l $boot_dir/loader
                ;;
            *)
                # Upgrade U-boot and Loader
                bootupgrade -u $boot_dir/uboot -l $boot_dir/loader
                ;;
            esac

        fi
        ;;

    *)
        ;;

    esac

    DebugOff bios_check
}

copy_conf()
{
    [ -z "$upgrade_with_config_files" ] || copy_conf_files config_destdir=$1 $upgrade_with_config_files
}

copy_conf_files()
{
    while :; do
	case $1 in
	*=*) eval $1; shift;;
	*) break;;
	esac
    done

    local DIR_UPGRADE_CONFIG=${config_destdir:=/config/upgrade-config}
    local FORMAT_UPGRADE_CONFIG=${upgrade_with_config_format:=text}
    [ -d $DIR_UPGRADE_CONFIG ] || mkdir $DIR_UPGRADE_CONFIG
    for each_conf in $*; do
	local cname="`basename $each_conf`.$FORMAT_UPGRADE_CONFIG"
	cp $each_conf $DIR_UPGRADE_CONFIG/$cname
    done
}

#!/bin/sh
#
# $Id: jinstall-header,v 1.62.66.2 2009-08-27 06:10:01 dtang Exp $
#
# Copyright (c) 2001-2013, Juniper Networks, Inc.
# All rights reserved.
#
# A common header used by all jinstall REQUIRE, INSTALL, and DEINSTALL
# scripts. Each time the script is called $1 is set to the package
# name and $2 is set to the instance. Based on the instance, the
# appropriate code gets executed.
#
# This script is run after the tar file has been unpacked into the /var
# sandbox area before anything has actually been moved to the final
# location, and then again after things have been moved into place.
#

rootdev_name=`df | awk '{if ($6 == "/") print $1 ;}'`
jinstall_rollback=/mfs/.jinstall_rollback
#
# file_size()
#
# Compute the amount of space used by a bunch of files
#
file_size() {
    echo `du -ks $* 2>/dev/null | awk '{ sum += $1 } END { print sum }'`
}

#
# package_size()
#
# Compute the amount of space used by an installed package.
#
package_size() {
    local files
    files=`pkg_info -qL "$1" 2>/dev/null | awk '{ print $1 }'`
    if [ ! -z "${files}" ]; then
	file_size ${files}
    else
	echo 0
    fi
}


# tmp_storage_check()
#
# Check to make sure when the installer copies files to the /tmp directory
# it has enough space
#
tmp_storage_check() {

    #
    # size the tmp based on the amount of memory available.
    #
    memsize=`sysctl -n hw.512bmem 2>/dev/null`
    if [ $? != 0 ]; then
	# older O.S. versions do not support "sysctl -n hw.512bmem",
	# however these versions do not have large memory either. We can use:
	memsize=`sysctl -n hw.physmem`
	memsize=`expr $memsize / 512`
    fi
    # the installer will save 24M for working, and allocate all
    # other free memory for mfs.  Allow for some slop.
    work_mem=`expr \( 24 \* 120 / 100 \) \* 2048`
    # we have 512 byte units, but the check below is in kbytes
    # so convert!
    available=`expr \( $memsize - $work_mem \) / 2`

    # but we won't use more that 1G (this is kbyte units)
    max_mfs=`expr 1024 \* 1024`
    if [ $available -gt $max_mfs ]; then
	available=$max_mfs
    fi

    #
    # sum the amount of space the configs will occupy
    #
    config_list=""
    [ -d /config ] && config_list="${config_list} /config"
    [ -d /var/config ] && config_list="${config_list} /var/config"
    config_suggested=`file_size $config_list`

    #
    # find out the amount of space the packages will occupy. This is
    # conservative. The bootstrap install space is added even though it
    # will not go on /tmp just to make calculations easy and allow for 
    # tmp file generated by the install script
    #
    package_suggested=`file_size $instmp`

    suggested=`expr ${package_suggested} + ${config_suggested}`

    if [ $suggested -ge $available ] ; then
	warn
	warn "The /tmp filesystem that is created by the next stage of"
	warn "the installer does not have sufficient space. This package"
	warn "requires ${suggested}k free (${config_suggested}k for configuration"
	warn "files and ${package_suggested}k for the new software), but there is"
	warn "only ${available}k available."
	dire_warn
    fi

}


# var_storage_check()
#
# Check that /var is not an emergency partition.
#
var_storage_check() {

    #
    # Check that /var is a hard disk, not an emergency var
    #
    vardrive=`df /var | grep -v Filesystem | awk '/^mfs|\/mfs$/ {print "emergency"}'`
    trace "*** /var is on - ${vardrive} - (empty means on hard disk)"
    if [ "$vardrive" = "emergency" ] ; then
	warn
	warn "The /var drive is not mounted on the hard disk. This package"
	warn "requires that /var be mounted on the hard disk."
	dire_warn
    fi

    #
    # Check that hard disk is in the Boot List.
    #
    model=`sysctl -n hw.re.model`

    case "$model" in
    teknor|force|kontron|emerson)
	sysctl -n machdep.bootdevs|grep -q disk
	if [ $? != 0 ] ; then
	  warn
	  warn "This installation will not succeed."
	  warn "This installation requires the presence of the hard disk."
	  warn "The hard disk is missing from the Boot List."
	  warn "Try pcmcia card installation, to install only on compact-flash."
	  warn
	  warn "This installation attempt will be aborted."
	  warn
	  exit 1
	fi
	;;
    esac
    #
    # available space on /var
    #
    available=`df -k /var | awk '$1 != "Filesystem" { print $4 }'`
    trace "*** free space on /var: ${available}"
    
    #
    # suggested = space needed by pkg_add playpen. Playpen size is
    # two times the size of the package.
    #
    fsize=`file_size .`
    suggested=${fsize}

    # Need more space if the image should be copied.
    if [ -z "$PKG_NO_COPY" ]; then
	suggested=`expr $suggested + $fsize`
    fi

    if [ $suggested -ge $available ] ; then
	warn
	warn "The /var filesystem is low on free disk space."
	warn "This package requires `expr ${suggested} - ${available}`k more space free."
	if [ -z "$PKG_NO_COPY" ]; then
	    warn "You have chosen to copy the image. You may opt not to copy it."
	fi
	dire_warn
    fi

}


#
# root_storage_check()
#
# Check to make sure we've got enough space in root to untar the
# bootstrap installer. 
#
root_storage_check() {

    #
    # If the jinstall target is compact-flash disk, check that it is
    # is in the Boot List.
    # Note: We do not check for hard disk because if it is not in the
    #       Boot List, jinstall will not pass the var_storage_check()
    #       anyway.
    #
    installdrive=`echo $rootdev_name | sed -n '/^\/dev\//s#^/dev/\([a-z]*[0-9]*\).*#\1#p'`
    [ -z "${installdrive##[wr]*}" ] && installdrive="a${installdrive#[wr]}"
    if [ "${installdrive#[rad][da]}" = "0" ] ; then
      model=`sysctl -n hw.re.model`

    case "$model" in
    teknor|force|kontron|emerson)
	sysctl -n machdep.bootdevs|grep -q compact-flash
	if [ $? != 0 ] ; then
	    warn
	    warn "This installation will not succeed."
	    warn "This installation requires the presence of the compact-flash."
	    warn "The compact-flash is missing from the Boot List."
	    warn
	    warn "This installation attempt will be aborted."
	    warn
	    exit 1
	fi
	;;
      esac
    fi
    #
    # available space on root
    # XXX there should be a sysctl to give us the device
    #
    eval `df -k | awk '$6 == "/" { print "rootdev=" $1, "available=" $4 }'`
    trace "*** free space on /: ${available}"

    #
    # we do not even want to play, if the boot device is too small.
    #
    rootdev_min=256
    # allow 10% slop to account for different manufacturers.
    rootdev_minsz=`expr \( $rootdev_min \* 90 / 100 \) \* 2048`
    rootdev_size=`disklabel ${rootdev%a} | sed -n '/sectors.unit:/s,.*:,,p'`
    if [ ${rootdev_size:-0} -lt $rootdev_minsz ]; then
	warn
	warn "This installation will not succeed."
	warn "The boot device is less than ${rootdev_min}M."
	warn "A hardware upgrade is required."
	warn
	exit 1
    fi
    #
    # suggested = space occupied by bootstrap-install
    #
    suggested=0
    if [ -f bootstrap-install*-15.1R7-S2.tar ]; then
	size=`tar tvf  bootstrap-install*-15.1R7-S2.tar | \
	      awk '{ sum = sum + ($3 / 1024) + 4 } END { print int(sum) }'`
	suggested=`expr ${suggested} + ${size}`
    fi

    #
    # Make sure root always has 2mb to spare. Remember, we'll get
    # lots more space back when the running daemons are restarted.
    #
    suggested=`expr ${suggested} + 2048`

    trace "*** suggested space: ${suggested}"
    
    if [ $suggested -ge $available ] ; then
	warn
	warn "The root filesystem is low on free disk space."
	warn "This package requires ${suggested}k free, but there"
	warn "is only ${available}k available."
	dire_warn
    fi
}

#
# abort_because_config()
#
# Print and diagnostic message and abort an installation
# because we've detected that config file system usage is
# currently higher than will fit in a new smaller file system
#
abort_because_config() {
    warn
    warn " Current /config file usage of $1 blocks may not fit"
    warn " in new smaller file system with estimated available $2."
    warn " /config file space usage is too close for repartitioning."
    warn " Free space in /config by setting 'system compress-configuration-files'"
    warn " before proceeding.  Installation aborted."
    warn
    exit 1
}

#
# config_storage_check()
#
config_storage_check() {
    local arch opts

    fsck -p /config  > /dev/null 2>&1
    if [ ! -e /config/vchassis ] ; then
       mount /config    > /dev/null 2>&1
    fi
    eval `df -b /config | \
	    awk '/s[1-2]e/ { print "diskname=" $1, "used=" $3, "available=" $4 }' | \
	    sed 's,/dev/\(.*s[1-2]\)e,\1,'`

    arch=`uname -m`
    case "$arch" in
        powerpc)
            opts="-m i386"
            ;;
        *)
            opts=""
            ;;
    esac

    if type bsdlabel > /dev/null 2>&1
    then
	disksize=`bsdlabel $opts $diskname | awk '/ c:/ { print $2 } '`
        disksize=${disksize:-0}
    else
	# Transition from disklabel(8) to bsdlabel(8)
	# Since we got here, it should be safe to assume we can defer
	# the installation of a new label and the disk to be big enough

	return
    fi

    used=${used:-0}

    #
    # anything less than 18600 blocks will fit on any flash disk ever shipped
    #
    if [ $used -gt 18600 ] ; then

        #
        # OK, we have a lot of used space, let's do some checking
        #

	# 122M disk or larger, config will be 10% of disksize
	if [ $disksize -ge 250848 ] ; then
	    #
	    # for this we make a conservative estimate,
	    # config # will be 10% of disksize,and 12%
	    # of that is allocated for overhead and roundup
	    #
	    configsize=`expr $disksize / 10`
	    overhead=`expr $configsize "*" 12 / 100`
	    available=`expr $configsize - $overhead`
	    if [ $used -gt $available ] ; then
		abort_because_config $used $available
	    fi

	# 80M to 122M, config will be fixed at 12M
	elif [ $disksize -gt 163808 ] ; then
	    if [ $used -gt 21844 ] ; then
		abort_because_config $used 21844
	    fi

	# the following should never happen
	# 76M, config will be 10M, to be complete
	elif [ $disksize = 156640 ] ; then
	    if [ $used -gt 18620 ] ; then
		abort_because_config $used 18620
	    fi
	fi
    fi

    # Additional config files can be given during upgrade.
    # Ensure there is enough space to store them into
    # /config/upgrade-config/ directory.
    if [ -n "$upgrade_with_config_files" ]; then
        local required=`du -c $upgrade_with_config_files | sed -n '$ s/\(.*\)total/\1/p'`

	if [ $available -lt ${required:-0} ]; then
	    warn
	    warn "/config has $available blocks available."
	    warn "Actual required storage space is $required blocks."
	    warn
	    exit 1
	fi
    fi

    #
    # We got here, we've checked the config size to be ok.
    #
}



# save_configs
#
# Save configs into a tar file called configs-<release>.tgz
#
save_configs() {
    local tgz=${1:-$PKG_PREFIX/configs-15.1R7-S2.tgz}
    local rc=0

    #
    # if this is occuring during a media installation (such as
    # installing on an olive with  floppies) the PKG_BOOTSTRAP will be
    # set and we can return immediately
    #
    if [ "$PKG_BOOTSTRAP" != "" ] ; then
	return $rc
    fi

    # check how much space is taken up in /var/tmp/preinstall
    # (without the config files)
    #
    # Check to see if the packlist contains a jggsn package
    # If so, available space will be higher
    #
    if exists /var/tmp/preinstall/*ggsn*; then
	space_avail=`expr 346920 / 2`
    else
	space_avail=`expr 327680 / 2`
    fi
    space_used=`file_size /var/tmp/preinstall`
    space_used=${space_used:-0}

    # calculate space left for config files
    if [ $space_avail -gt $space_used ]
    then
	space_left=`expr $space_avail - $space_used`
    else
	space_left=0
    fi
    
    # based upon size of juniper.conf.1.gz file, determine
    # how many config files (max 10) we should save.
    conf1=`Exists /config/juniper.conf.1.gz /var/db/config/juniper.conf.1.gz \
                  /config/juniper.conf.?.gz /var/db/config/juniper.conf.?.gz`
    if [ -f "$conf1" ] ; then
        conf1_sz=`file_size $conf1`
        if [ $conf1_sz -gt 0 ]; then
            num_save=`expr $space_left / $conf1_sz`
            if [ $num_save -gt 10 ]; then
                num_save=10
            fi
        fi
    fi
    num_save=${num_save:-10}

    inform "Saving the config files ..."

    save_current_configuration

    config_list=""

    # dirs that we need to preserve
    save_dir_list="config \
var/db \
var/preserve \
"

    for d in $save_dir_list
    do
        [ -d /$d ] || continue
        config_list="${config_list} $d"
    done

    if [ -f "$config_changes" ] ; then
	local f
	f=`echo $config_changes | sed -e 's,^/,,'`
	config_list="${config_list} $f"
    fi

    ssh_dir="etc/ssh"
    # srx package use /cf/etc/ssh instead of /etc/ssh
    if [ -d "/cf/etc/ssh" ]; then
        ssh_dir="cf/etc/ssh"
    fi

    ssh_list=`echo /${ssh_dir}*`
    if [ "$ssh_list" != "/${ssh_dir}*" ] ; then
	local f g
	for f in $ssh_list ; do 
	    g=`echo $f | sed -e 's,^/,,'`
	    config_list="${config_list} $g"
	done
    fi

    #
    # save the loader.conf as a separate file. We would like to copy
    # some lines from the file once we are done with jinstall  
    if [ -f /boot/loader.conf -a -d /var/tmp ] ; then
	cp /boot/loader.conf /var/tmp/preinstall_boot_loader.conf
    fi

    # we now wack /var/etc/*.conf before restoring these,
    # so make sure we keep critical ones.
    save_file_list="etc/rc.custom \
var/etc/group \
var/etc/master.passwd \
var/etc/inetd.conf \
var/etc/pam.conf \
var/etc/resolv.conf \
var/etc/syslog.conf \
var/etc/localtime \
etc/localtime \
var/etc/exports \
var/etc/extensions.allow \
var/tmp/baseline-config.conf \
var/tmp/preinstall_boot_loader.conf
"
    for f in $save_file_list ; do
	[ -f "/$f" ] && config_list="${config_list} $f"
    done

    if [ "$config_list" != "" ] ; then
	# If/when we have more files to exclude we can use
	# --exclude-from file
	# Note that -czf is required rather than cfz
	if [ $num_save -lt 10 ] ; then 
	    # all config files numbered $num and greater should be excluded
	    tar -czf $tgz -C / --exclude ${ssh_dir}/primes \
		--exclude "var/db/*+" \
		--exclude "var/db/config/juniper.conf.[$num_save-9].gz" \
		--exclude "var/db/config/juniper.conf.?[0-9].gz" \
		--exclude "var/db/alarm.db" \
		--exclude "var/db/ovsdatabase" \
		--exclude "var/db/transport.db" \
		 $config_list
	else
	    # all config files numbered 10 and greater should be excluded
	    tar -czf $tgz -C / --exclude etc/ssh/primes \
		--exclude "var/db/*+" \
		--exclude "var/db/config/juniper.conf.?[0-9].gz" \
		--exclude "var/db/alarm.db" \
		--exclude "var/db/ovsdatabase" \
		--exclude "var/db/transport.db" \
		 $config_list
	fi
	rc=$?
	if [ $rc != 0 ] ; then
	    warn
	    warn "Backup of configuration files failed"
	    warn
	    dire_warn
	fi
    fi
    return $rc
}

# the data we need to save for install phase must
# fit in the min of available memory and max32bit
# hw.usermem as we see it here is considerably
# less than that available during MFS, so we use 
# hw.physmem less 30M (but in kbytes)
physmem=`sysctl -n hw.physmem`
memKb=`expr $physmem / 1024 - 30 \* 1024`
# use 3G as limit
max32bitKb=$(( 3 * 1024 * 1024 ))
maxIntKb=$(( 2 * 1024 * 1024 ))

check_32bit_sane() {
    local used=${1:-0}
    local rc=0
    local reason=

    DebugOn check_32bit_sane
    if [ $used -ge $max32bitKb ]; then
	reason="32bit addressable memory ($max32bitKb)"
    elif [ $used -ge $memKb ]; then
	local machine=`uname -m`
	case "$machine" in
	amd64) # we do not ship amd64 RE's with < 3G
	    # but an older kernel may truncate the answer given
	    # for hw.physmem to 32bit sysctl.
	    if [ $used -gt $maxIntKb ]; then
		# we could have a problem if this is an olive
		model=${model:-`sysctl -n hw.re.model`}
		case "$model" in
		olive) reason="physical? memory ($maxIntKb)";;
		esac
	    fi
	    ;;
	*) reason="physical memory ($memKb)";;
	esac
    fi
    if [ -n "$reason" ]; then
	error_more "The size of saved data exceeds $reason"
	error_more "Use: 'request system storage cleanup'"
	rc=1
    fi
    DebugOff check_32bit_sane
    return $rc
}


# uninstall_configs
#
# Delete the config tarball
#
uninstall_configs() {

    inform "Deleting saved config files ..."
    rm -f $PKG_PREFIX/configs-15.1R7-S2.tgz

}

set_active_slice_acx()
{
    pkg_clean_files=/tmp/.pkgcf$$
    root_dev=/dev/$(read_link /dev/root)
    BOOT_DEV=${root_dev%s[0-9][a-z]}
    echo $1 | sed 's/.*s\([0-9]\)[a-z]/a \1/' > /tmp/fdisk.conf.$$
    echo "/tmp/fdisk.conf.$$" >> $pkg_clean_files
    fdisk -f /tmp/fdisk.conf.$$ $BOOT_DEV > /dev/null
}

#
# install_bootstrap <bootstrap-install-pathname>
#
# Installs the bootstrap installer, and rewrites the boot block so 
# that the next reboot gives control to the bootstrap installer
#
install_bootstrap() {
    local arch

    #
    # if this is occuring during a media installation (such as
    # installing on an olive with  floppies) the PKG_BOOTSTRAP will be
    # set and we can return immediately
    #
    if [ "$PKG_BOOTSTRAP" != "" ] ; then
	return
    fi

    inform "Installing the bootstrap installer ..."

    #
    # On ACX Platforms Root is Read Only, So update on other  
    # slice.
    #
    productmodel=${productmodel:-`/sbin/sysctl -n hw.product.model 2>/dev/null`}
    case "$productmodel" in
	acx*)
	    if [ -d "/mfsbin" ] ; then
		echo "copying files to /altroot"
	        target_partition=`sysctl -n hw.re.dualroot.alt_root`
	        mount $target_partition /altroot
		
		prepare_bootstrap "/altroot" || fail=1
		set_active_slice_acx /dev/$(read_link /dev/altroot)
		umount /altroot
	    else
		prepare_bootstrap "/" || fail=1
	    fi
		;;
	*)
		prepare_bootstrap "/" || fail=1
		;;
    esac

    if [ "$fail" = "1" ] ; then
	warn
	warn "Install of the bootstrap installer failed"
	warn
	uninstall_bootstrap
	warn_abort
    fi

    trace "Installing new boot loaders"

    labeldrive=`echo $rootdev_name | sed -nE '/^\/dev\//s#^/dev/([a-z]+[0-9]+(s[0-9]+)?).*#\1#p'`

    [ -z "${labeldrive##[wr]*}" ] && labeldrive="a${labeldrive#[wr]}"
    installdrive=${labeldrive%s[0-9]*}

    if ! type bsdlabel > /dev/null 2>&1
    then
	# Transition from disklabel(8) to bsdlabel(8)
	# Since we got here, it should be safe to assume we can defer
	# the installation of a new label and skip installing a new bootstrap loader

	return
    fi

    arch=`uname -m`
    if [ $arch != "powerpc" ] ; then 
        bsdlabel -B -b /boot/boot $labeldrive
	if [ $? != 0 ] ; then
	    warn
	    warn "Failed while trying to install bootstrap loaders"
       	    warn
       	    uninstall_bootstrap
       	    warn_abort
	fi
    fi

    if [ "${installdrive#[rad][da]}" != "0" ] ; then
	model=`sysctl -n hw.re.model`
	re_type=`sysctl -n hw.re.type`
	case "$model:re_type" in
	#  RE-A-1800x2,RE-S-1800x[24] and RE-TXP-SFC/RE-TXP-LCC:
	kontron:2[234]|emerson:*)
	    sysctl 'machdep.nextbootdev=disk1' > /dev/null 2>&1
	    ;;
	teknor*|force*|kontron*)
	    sysctl -w 'machdep.nextbootdev=disk' > /dev/null 2>&1
	    ;;
	cpv5000)
	    sysctl -w 'machdep.bootsuccess=2' > /dev/null 2>&1
	    ;;
	esac
    fi
}

prepare_bootstrap() {
    if [ -f $jinstall_rollback ]; then 
	rm -f $jinstall_rollback
    fi

    (
	for f in `tar tf $PKG_PREFIX/bootstrap-install*-15.1R7-S2.tar`; do
	    file=$1/$f
	    if [ ! -f $file ]; then
		echo "/bin/rm -f $file"
		continue
	    fi
	    dname=${f%/*}; bname=${f##*/}
	    dfile=$1/$dname/.$bname.backup
	    mv $file $dfile
	    echo "mv -f $dfile $file"
	done
    ) > $jinstall_rollback

    tar xf $PKG_PREFIX/bootstrap-install*-15.1R7-S2.tar -C $1 || return 1	
}


# uninstall_bootstrap
#
# Undo the effects of untarring the bootstrap installer. 
#
uninstall_bootstrap() {
    if ! type bsdlabel > /dev/null 2>&1
    then
	# Transition from disklabel(8) to bsdlabel(8)
	# defer removing the bootstrap installer

	return
    fi

    inform "Deleting bootstrap installer ..."

    productmodel=${productmodel:-`/sbin/sysctl -n hw.product.model 2>/dev/null`}
    case "$productmodel" in
	acx*)
	    if [ -d "/mfsbin" ] ; then
		target_partition=`sysctl -n hw.re.dualroot.alt_root`
		mount $target_partition /altroot
		if [ -f $jinstall_rollback ]; then
		    sh $jinstall_rollback >/dev/null
		    /bin/rm -f $jinstall_rollback
		fi
		set_active_slice_acx /dev/$(read_link /dev/root)
		umount /altroot
	    else
		if [ -f $jinstall_rollback ]; then
		    sh $jinstall_rollback >/dev/null
		    /bin/rm -f $jinstall_rollback
		fi
	    fi
	    ;;
	*) 
	    if [ -f $jinstall_rollback ]; then
		sh $jinstall_rollback >/dev/null
		/bin/rm -f $jinstall_rollback
	    fi
	    ;;	
    esac
}

#
# create_settings_file <settings-file>
#
# Create a file with all the settings for the bootstrap-installer
#
create_settings_file() {
    local altdrive=""
    local slice=""

    installdrive=`echo $rootdev_name | sed -n '/^\/dev\//s#^/dev/\([a-z]*[0-9]*\).*#\1#p'`
    slice=`echo $rootdev_name | sed -n '/^\/dev\//s#^/dev/\([a-z]*[0-9]*\)\(s[0-9]*\).*#\2#p'`

    # if mirroring is enabled, install on mirror subdisk as well
    if [ "$installdrive" = "rd0" ] ; then
	altdrive=`cat /etc/fstab | awk '$2 == "/altroot" {print substr($1, 6, 3)}'`
    fi
    [ -z "${installdrive##[wr]*}" ] && installdrive="a${installdrive#[wr]}"

    echo "installdrive='${installdrive} ${altdrive}'" > $1
    echo "currslice='${slice}'" >> $1
    echo "ospackage=jboot-ex-15.1R7-S2.tgz" >> $1
    echo "osedition=domestic" >> $1
    echo "osrelease=15.1R7-S2" >> $1
    echo "packlist='jbundle-ex-3300-15.1R7-S2-domestic.tgz'" >> $1

    if [ -f $PKG_PREFIX/configs-15.1R7-S2.tgz ] ; then
	echo "configpackage=configs-15.1R7-S2.tgz" >> $1
    fi

    if [ ! -z "$PKG_TRACE_SHELL" ] ; then
	echo "set -x" >> $1
    fi
}

# installed_sdk_packages_check()
#
# This routine prints out SDK packages that will have to be installed again 
# when JUNOS is being upgraded 
#
installed_sdk_packages_check() {
    local pkg_certs pkg_provider_id skip_print
    for pkg in /opt/sdk/service-packages/*;
	do
	[ -d "$pkg" ] ||continue
	pkg_dir="/opt/sdk/service-packages/${pkg##*/}"
	for p in $pkg_dir/${pkg##*/}-*
	    do
		if [ -e $p ]; then
		    pkg_certs=packages/certs.pem
		    tar -x $pkg_certs -zf $p
		    if [ -s "$pkg_certs" ]; then
			pkg_provider_id=`x509-exts -x "jnxProviderId" "$pkg_certs"`
			    if [ "$pkg_provider_id" ]; then
				${skip_print} warn "The following SDK packages will need to be reinstalled:"
				warn "${pkg##*/}"
				skip_print=:
			    fi
		    fi
		    rm -rf $pkg_dir/packages
		else
		    warn "${pkg##*/} package is missing"
		fi
	    done
    done

    for pkg in /etc/db/pkg/*;
	do
	[ -f "$pkg/+COMMENT" ] || continue
	pkg_certs=`Exists /packages/mnt/${pkg##*/}/pkg/manifest.certs \
	                  /packages/mnt/${pkg##*/}/pkg/certs.pem`
	if [ "$pkg_certs" ]; then
	    pkg_provider_id=`x509-exts -x "jnxProviderId" "$pkg_certs"`
	    if [ "$pkg_provider_id" ]; then
		${skip_print} warn "The following SDK packages will need to be reinstalled:"
		warn "${pkg##*/}"
		skip_print=:
	    fi
	fi
    done
}

#
# preinstall_dialogue()
#
# This is the dialogue or monologue to inform the user what is going to happen.
#
preinstall_dialogue() {

    warn
    warn "    This package will load JUNOS 15.1R7-S2 software."
    warn "    It will save JUNOS configuration files, and SSH keys"
    warn "    (if configured), but erase all other files and information"
    warn "    stored on this machine.  It will attempt to preserve dumps"
    warn "    and log files, but this can not be guaranteed.  This is the"
    warn "    pre-installation stage and all the software is loaded when"
    warn "    you reboot the system."
    warn

}


# request_reboot
#
# This routine prints out the reboot instructions. Previously it would
# get a response from the user at the end of the install if they
# would like to proceed, but that turned out to be tricky. See PR14859
#
request_reboot() {

    warn
    warn "    A REBOOT IS REQUIRED TO LOAD THIS SOFTWARE CORRECTLY. Use the"
    warn "    'request system reboot' command when software installation is"
    warn "    complete. To abort the installation, do not reboot your system,"
    warn "    instead use the 'request system software delete jinstall'"
    warn "    command as soon as this operation completes."
    warn
   
    return
}
#!/bin/sh
#
# $Id: INSTALL 584333 2013-06-03 21:26:11Z ib-builder $
#
# Copyright (c) 2001-2013, Juniper Networks, Inc.
# All rights reserved.
#
# OS Update package installation script
#
# Most of the procedures are defined in jinstall-header. This script
# merely contains the logic.
#
#----------------------------------------------------------------------
# Main script
#----------------------------------------------------------------------

initialize "$@"

case ${instance} in
    PRE-INSTALL)
	;;
    POST-INSTALL)
	tar zxf $PKG_PREFIX/jbundle-ex-3300-15.1R7-S2-domestic.tgz -C $PKG_PREFIX jboot*.tgz
	create_settings_file $PKG_PREFIX/install.conf
	echo "junos_ex=junos-ex-3300" >> ${PKG_PREFIX}/install.conf
	;;
    *)
	exit 1
	;;
esac

exit 0
