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

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

pkg_LCK=/tmp/.pkg.LCK
pkg_db_dir=/etc/db/pkg
pkg_tag=
fail=0
sw_pkgdir=/var/sw/pkg
opt_pkgdir=/opt/sdk/pkg
pkg_unsup=/etc/notices/unsupported.txt
pkg_supported_ltrs=BRSWX

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

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

jkernel_require=/var/run/jkernel.require

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

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

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

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

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

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

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

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

rm_symlink_package() {
    case "$package" in
    jbase|jbase-ex|jroute|jroute-ex|jkernel|jkernel-ex|jpfe*|jdocs)
        [ "$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 X,$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
    case "$package" in
    jbase|jbase-ex|jroute|jroute-ex|jkernel|jkernel-ex|jpfe*|jdocs)
        [ "$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)
        [ "$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
}

# Function to perform name checks for JUNOS SDK packages
sdk_check_symlinks () {
    local target="$1"

    case "$target" in
    "/opt/lib/dd/lib$PKG_PROVIDER_NAME"*"-dd.so" | \
    "/opt/lib/render/lib$PKG_PROVIDER_NAME"*"-render.so" | \
    "/opt/lib/dd/$PKG_PROVIDER_NAME"*".dml" | \
    "/var/db/scripts/op/$PKG_PROVIDER_NAME"* | \
    "/var/db/scripts/event/$PKG_PROVIDER_NAME"* | \
    "/var/db/scripts/commit/$PKG_PROVIDER_NAME"*) ;;
    *"lib"*"dd.so" | *"lib"*"render.so" | *".dml" | \
    "/var/db/scripts/"*)
        error "$target does not have $PKG_PROVIDER_NAME";;
    *) ;;
    esac
}

package_sdk_post_install() {
    DebugOn package_sdk_post_install
    mkdir -p /var/packages
    rm -f $base_mountpkg /var/packages/mount.$package
    ln -s $base_pkgdir/mount.$pkgfile /var/packages/mount.$package
    ln -s /var/packages/mount.$package $base_mountpkg
    DebugOff package_sdk_post_install
}

package_sdk_deinstall() {
    DebugOn package_sdk_deinstall
    rm -f /var/packages/mount.$package
    DebugOff package_sdk_deinstall
}

package_sdk_post_deinstall() {
    DebugOn package_sdk_post_deinstall
    cleanup_package $package /dev/null
    if [ "$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
    DebugOff package_sdk_post_deinstall
}

package_sdk_subpkg_type() {
    DebugOn package_sdk_subpkg_type
    if tar -tz --fast-read -f $subpkg_path +CONTENTS >/dev/null 2>&1; then
	pkg_info -oq $instmp/$subpkg_name
    elif tar -tz --fast-read -f $subpkg_path +junos-package.xml >/dev/null 2>&1; then
	tar -zxO --fast-read -f "$subpkg_path" +junos-package.xml | sed -n -e '/<type>/s,.*<type>\([^<]*\)</type>.*,\1,p' 2>/dev/null
    fi
    DebugOff package_sdk_subpkg_type
}

package_sdk_bundle_post_install() {
    DebugOn package_sdk_bundle_post_install
    for subpkg in  ; do
        subpkg_path=`Exists $instmp/$subpkg-*12.1X46-D40.2*.tgz`
        if [ ! -f "$subpkg_path" ]; then 
            echo "Can't find $subpkg"; 
            fail=1; 
            continue;
        fi
        subpkg_name=`basename $subpkg_path`
        subpkg_type=`package_sdk_subpkg_type`
        case $subpkg_type in
        SDK_PKG_RE|SDK_PKG_CNTR)
            pkg_info -e $subpkg && { \
                echo "Auto-deleting old $subpkg ...";
                pkg_delete $subpkg || \
                { fail=1; continue; }
            }
            echo "Installing new $subpkg ..."
            export PKG_VERIFIED=
            pkg_add $PKG_FORCE $subpkg_path || \
            { fail=1; continue; }

            ;;
        *)
            echo "Package type $subpkg_type is not supported"
            fail=1;
            continue;
            ;;
        esac
    done
    DebugOff package_sdk_bundle_post_install
}

package_sdk_cntr_post_install() {
    DebugOn package_sdk_cntr_post_install
    sdk_pkgdir=/opt/sdk/service-packages/junos
    if [ ! -d $sw_pkgdir ]; then
        echo "Creating $sw_pkgdir ... "
        mkdir -p $sw_pkgdir || { fail=1; break; }
    fi
    if [ -d $sdk_pkgdir ]; then
        echo "Cleaning $sdk_pkgdir ..."
        rm -rf $sdk_pkgdir
    else
        echo "Creating $sdk_pkgdir ..."
    fi
    mkdir -p $sdk_pkgdir || { fail=1; break; }
    for subpkg in  ; do
        subpkg_path=`Exists $instmp/$subpkg-*12.1X46-D40.2*.tgz`
        if [ ! -f "$subpkg_path" ]; then 
            echo "Can't find $subpkg"; 
            fail=1; 
            continue; 
        fi
        subpkg_name=`basename $subpkg_path`
        subpkg_type=`package_sdk_subpkg_type`
        case $subpkg_type in
        SDK_PKG_PIC)
            echo "Storing $subpkg_name in $sw_pkgdir ..."
            cp $subpkg_path $sw_pkgdir || { fail=1; continue; }

            echo "Link: $sdk_pkgdir/$subpkg -> $sw_pkgdir/$subpkg_name..."
            ln -sf $sw_pkgdir/$subpkg_name $sdk_pkgdir/$subpkg || \
            { fail=1; continue; }
            ;;
        *)
            echo "Package type $subpkg_type is not supported"
            fail=1;
            continue;
            ;;
        esac
    done
    if [ -z "$PKG_BOOTSTRAP" ] ; then
	echo "Notifying mspd ..."
	daemon_send_signal HUP mspd
    fi
    DebugOff package_sdk_cntr_post_install
}

package_sdk_cntr_deinstall() {
    DebugOn package_sdk_cntr_deinstall
    sdk_pkgdir=/opt/sdk/service-packages/junos
    echo "Removing $sdk_pkgdir ..."
    rm -rf $sdk_pkgdir
    for subpkg in  ; do
        subpkg_path=`Exists $sw_pkgdir/$subpkg-*12.1X46-D40.2*.tgz`
        if [ -f "$subpkg_path" ]; then
            subpkg_name=`basename $subpkg_path`
            echo "Removing $subpkg_name from $sw_pkgdir ..."
            rm -f $subpkg_path
        fi
    done
    echo "Notifying mspd ..."
    daemon_send_signal HUP mspd
    DebugOff package_sdk_cntr_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' - that is an important nullfs mount for J-Web
    #
    mount | sed -n -e "/ufs,/d" -e "/devfs,/d" -e "/\/jail\/var/d" -e "/mnt\/$pkgmatch/s,mnt/,mnt ,p" |
    while read mddev j1 j2 mounted_package j3
    do
	# this helps debug issues...
	: mddev=$mddev mounted_package="$mounted_package" ignore="$ignore"
	echo ${mounted_package##*/} >> $mounted
        case "$mounted_package" in
	$ignore) trace skipping $ignore
            continue
            ;;
	$backup) trace skipping $backup
            continue
            ;;
	esac
        trace cleaning up $mounted_package
        [ -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
	    rm -f $base_pkgdir/umount.$mounted_package
	else
	    # communicating to the parent of a redirected
	    # loop can be a pain...
	    echo $pkgdir_mnt/$mounted_package >> $needclean
	fi
        if [ -s $base_pkgdir/mount.$mounted_package ]; then
            # see if it can tell us where the pkgfile is
            eval `grep pkgpath= $base_pkgdir/mount.$mounted_package; :`
        fi
        pkgpath=${pkgpath:-$pkgdir/$mounted_package}
        rm -f $base_pkgdir/mount.$mounted_package
        rm -df $pkgdir_mnt/$mounted_package 2>/dev/null
        chflags noschg $pkgpath $pkgpath.md5 $pkgpath.sha1 >/dev/null 2>&1
        rm -f $pkgpath $pkgpath.md5 $pkgpath.sha1
    done
    if [ -s $needclean ]; then
	clean_pkg_list="$clean_pkg_list $package"
	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
}

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

    cleanup_package $package $pkgfile

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

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

    # Only do this for non-release builds (and not customer-built sdk packages)
    case X,$PKG_PROVIDER_NAME 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
    NOTICES_ISSUED=:
    export NOTICES_ISSUED
}

#
# 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-12.1X46-D40.2.
    # base_* are the canonical locations - known to /etc/rc et al
    # the distinction between base_pkgdir and pkgdir is that for
    # packages like jdiag and jtools pkgdir may be set to
    # /var/packages so that the .iso will be kept off the flash.
    pkgfile=junos-srxsme-12.1X46-D40.2-domestic.tgz
    base_pkgdir=/packages
    pkgdir=${pkgdir:-$base_pkgdir}
    pkgdir_mnt=$base_pkgdir/mnt
    base_mountdir=$pkgdir_mnt/$package
    base_mountpkg=$base_pkgdir/mount.$package
    base_umountpkg=$base_pkgdir/umount.$package
    finish_install=$base_pkgdir/finish-install.$package
    finish_deinstall=$base_pkgdir/finish-deinstall.$package

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

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

    # jbundle and/or package.sh set this to a file, so that
    # we can detect across packages that a reboot is needed.
    PKG_NEED_TO_REBOOT=${PKG_NEED_TO_REBOOT:-/dev/null}
    if [ -s $PKG_NEED_TO_REBOOT ]; then
        . $PKG_NEED_TO_REBOOT
    fi
    pkg_origin=`sed -n '/^@comment.*ORIGIN:/ { s,.*ORIGIN:[[:space:]]*,,p;q; }' +CONTENTS 2> /dev/null`

    $NOTICES_ISSUED issue_notices
    DebugOff initialize
}

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


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


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

    product_model=`sysctl -n hw.product.model`
    re_model=`sysctl -n hw.re.model`
    case "$1:$product_model:$re_model" in
    *:olive) ;;			# ok
    jseries:j[1-9][0-9][0-9][0-9]:*) ;; # ok

    # Don't accept JSR image to load on pepsi class boxes , i.e
    # j2300, j4300, j6300. however we do accept it for in house
    # development.
    jsr:jsr[1-9][0-9]00:*|jsr:j[1-9][0-9]00:*)
        perms=$(expr $(smbc -o 0x30 0x57 1 | tail -1) : '.*\([0-9a-f]\)$')
        case $perms in
        2) 
        ;; # ok
        *)
        Error "Unsupported platform $product_model for JUNOS JS," \
              "use a jseries package"
        ;;
        esac
        ;;

    jseries:jsr[1-9][0-9][0-9][0-9]:*) ;; # ok
    jsr:jsr[1-9][0-9][0-9][0-9]:*) ;; # ok
    # 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

    vsrx:vsrx[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"
        ;;
    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
    local current=`sed 's,.*\[\([1-9][0-9.]*\).*,\1,' /etc/db/pkg/junos/+COMMENT`
    local min_release=${1:-12.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
	*/jbundle*) # nothing removed yet, so no need to rollback.
	    ;;
	*)  # previous package has likely been removed so be helpful.
	    warn
	    warn "Or use the command:"
	    warn
	    warn "	'request system software rollback'"
	    warn
	    warn "to attempt to restore the previous software set."
	    ;;
	esac
	warn
	warn "This installation attempt will be aborted."
	warn
	Exit 1
    fi
    DebugOff version_check
}

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

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

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

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

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

	    run_hooks storage_check_fail_hooks

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

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

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

    PKG_SETUP_VARIABLES_ONLY=TRUE

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

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

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

    # 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 [ -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() {
    echo "Restarting $1 ..."
    daemon_send_signal TERM "$1"
}

#
# daemon_restart <daemon-name>
#
# restart a daemon by whatever means available; normally, this means that
# we kill it (using rpdc is possible) and init restarts it
#
daemon_kill() {
    local rc
    if [ -x /usr/sbin/rpdc ]; then
	rpdc -q -D$1 stop
	rc=$?
    else
        rc=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*) 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 [ "$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
}

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

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

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

EOF
    if [ ! -x /sbin/mount_iso ]; then
	error "Cannot find /sbin/mount_iso!"
    fi
    echo "exec /sbin/mount_iso --force $pkgpath $mountpoint $package"
    
    DebugOff create_mount_package
}

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

create_umount_package () {
    DebugOn create_umount_package
    local pkgpath mountpoint

    pkgpath=$1
    mountpoint=$2

    if [ ! -x /sbin/umount_iso ]; then
	error "Cannot find /sbin/umount_iso!"
    fi
    echo "exec /sbin/umount_iso $pkgpath $mountpoint $package"

    DebugOff create_umount_package
}

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

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

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

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


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

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

check_sdk_version()
{
	if [ -z "$current_sdk_version_major" ]; then
		dot_run_require jbase
		dot_run_require junos
		current_sdk_version_major=${current_junos_sdk_version_major:-$current_jbase_sdk_version_major}
		current_sdk_version_minor=${current_junos_sdk_version_minor:-$current_jbase_sdk_version_minor}
		current_major=${current_junos_major:-current_jbase_major}
		current_minor=${current_junos_minor:-current_jbase_minor}
		current_sdk_compat=${current_junos_sdk_compat:-$current_jbase_sdk_compat}
	fi
 
	if [ ${current_sdk_version_major:-0} != 5 ] || [ ${current_sdk_version_minor:-0} -lt 4 ]; then
		error "JUNOS version incompatible - source compatibility supported from ${current_sdk_compat:-0.0} - ${current_major:-0}.${current_minor:-0}"
	fi
}

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-TXP-LCC|RE-DUO-1800|RE-DUO-2600|RE-JCS1200-1x2330|Olive)
        machine_compat_list="i386 amd64"
        ;;
    RE-S-1800x2|RE-S-1800x4|RE-A-1800x2)
        if [ "$1" = "jdiag" ]; then
            machine_compat_list="i386 amd64"
        else
            machine_compat_list="amd64"
        fi

        # Allow 32 bit packages to be installed with a warning when force
        # option is specified
        if [ "x$PKG_FORCE" != x ]; then
            warn_flag=true;
        fi
        ;;
    *)
        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
    *" mips "*) ;;
    *) if [ "$warn_flag" = true ]; then
           warn "Package $1 is not compatible - mips vs {$machine_compat_list}"
       else
           Error "Package $1 is not compatible - mips vs {$machine_compat_list}"
       fi
       ;;
    esac
}

check_cores_access()
{
    # Take parameters from junos-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/junos.access ]; then 
        echo "Removing old $opt_pkgdir/junos.access"
        rm $opt_pkgdir/junos.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 junos can not be installed: sharing violation."
            echo "    junos 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 junos can not be installed: sharing violation."
            echo "    junos 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/junos.access
cores_access=$pkg_cores_access
cores_sharing=$pkg_cores_sharing
EOF
    
    return 0
}

#
# selective_update_version_check
#
# Check selective-update package against base OS
#
selective_update_version_check() {
    local current=`sed 's,.*\[\([1-9][0-9.R|S|X|I]*\).*,\1,' /etc/db/pkg/junos/+COMMENT`

    if [ "$current" = "$1" ]; then
	return 0
    else
	echo "Package junos can not be installed: Incompatible base version";
    fi

    return 1
}

#
# selective_update_need_reboot
#
# Fail selective-update package installation if reboot is needed
#
selective_update_needs_reboot() {
    if [ -z "$PKG_USER_WILL_REBOOT" ]; then

	warn
	warn "    This pkg needs reboot option. Use the 'reboot' option"
	warn "    with 'request system software add' command to proceed"
	warn "    with the installation."
	warn

	return 1
    fi

    return 0
}

#
# selective_update_request_reboot
#
# Warn the user to reboot the system once selective-update package delete
# is complete
#
selective_update_request_reboot() {

    warn
    warn "    A REBOOT IS REQUIRED TO UNLOAD THIS SOFTWARE CORRECTLY. Use the"
    warn "    'request system reboot' command when software deletion is"
    warn "    complete."
    warn
   
    return
}

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-2007, 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 || (fips-mode) 2> /dev/null
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

    hash=$1

    if [ -s $hash ]; then
	case "$hash" in
	*sig) # real signature file
	    hash_cmd=/sbin/verify-sig
	    ;;
	*md5)  hash_cmd=/sbin/md5
	    hash_ext=md5
	    hash_name=MD5
	    ;;
	*sha1)	hash_cmd=/sbin/sha1
	    hash_ext=sha1
	    hash_name=SHA1
	    ;;
	*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

    # check if running system supports esig
    # a bit pessimistic but safe
    case `uname -r` in
    #  removing the next line causes .esig files to be passed
        [1-9].*|1[0-3].*) esigs= ;;
        *) esigs=esig;;
    esac

    for f in $*
    do
	[ -s $f ] || continue
	case $f in
	*.esig)
        [ -n "$esigs" ] || continue
        verify_hash $f
                ;;
	*.sha256|*.sha1|*.md5|*.sig)
	    verify_hash $f
	    ;;
	*)  # try in our order of preference
        if [ -n "$esigs" ]; then
            es=$f.esig
        else
            es=
        fi
	    for h in $es $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$$
    local product_model=`sysctl -n hw.product.model`
    local keywords="ata|cid|serialid|model"

    # Add platform specific keywords
    case "$product_model" in
    "vjx1000")
	keywords="${keywords}|retype"
	;;
    "firefly-perimeter")
	keywords="${keywords}|hw.chassis"
	;;
    *)
	# Unsupported platforms
	return
	;;
    esac

    # To preserve the old senstive values upon upgrade
    if [ -s /boot/loader.conf ]; then
        cat /boot/loader.conf | egrep -e "(${keywords}${1:+|$1})" > $tmpfile
    fi 

    [ -s $tmpfile ] && mv $tmpfile /boot/loader.tweaks
    rm -f $tmpfile
}

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
}
#!/bin/sh
#
# $Id$
#
# Copyright (c) 2001-2004, 2006-2007, Juniper Networks, Inc.
# All rights reserved.
#
# OS Update package installation script
#

initialize "$@"

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

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

    # we are not a normal package...
    pkgfile=junos-srxsme-12.1X46-D40.2-domestic
    jboot=junos-boot-srxsme-12.1X46-D40.2.tgz
    junos=junos-12.1X46-D40.2-domestic
    jpfe=jpfe-12.1X46-D40.2.tgz
    preinstall=/var/tmp/preinstall

    # Backup master.passwd and spwd.db. In case
    # something goes wrong during boot time commit,
    # we will use this for restoration to ensure 
    # that local login works fine.
    # Note: These backup files will be removed
    # after first boot.
    cp -p /cf/etc/spwd.db /var/etc/master.passwd /config  2>/dev/null

    # As to SRX BRANCH box, /cf/var/etc/master.passwd is a symlink
    # and need to point to /var/etc/master.passwd,
    # during config validation phase, this symlink don't exist,
    # and pwd_mkdb can't find master.passwd and failed,
    # so we create this symlink here.
    if [ "srxsme" = srxsme -a "x$ALT_ROOT_MNT" = x ]; then
        ln -sf /var/etc/master.passwd /cf/var/etc/master.passwd > /dev/null 2>&1
        cp -p /cf/etc/*.db /cf/etc/passwd /cf/var/etc 2>/dev/null 
    fi

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

    [ "$PKG_VALIDATING" ] || check_edition

    # ALT_ROOT_MNT will be defined only for dual-root installation.
    # So for single-root systems case $CF will always refer to /cf
    # For dual root systems it will refer to /altroot/cf
    CF=$ALT_ROOT_MNT/cf

    if [ -d $CF ]; then
	# create non empty first reboot file. On next boot, rc.chroot
	# script will look for this file. If its present, it will
	# remove the file and wont tell mgd -I for optimization.
	[ -d /var/sw/pkg ] && echo "Automatically generated file, rc.chroot will delete it on " \
	    "next reboot.  The presence of this file indicates that this " \
	    "is the first reboot after install/rollback and startup scripts," \
	    "like rc.chroot, will not use mgd -I for optimization." \
        >  /var/sw/pkg/.firstrebootfile

        # There's nothing very tricky about jboot anymore
        # we can just update now.
        trace Updating jboot...
        save_loader_tweaks

        chflags noschg $CF/sbin/preinit.bak 2> /dev/null
        rm -f $CF/sbin/preinit.bak
        if exists /usr/lib/libc.so.4; then
            # we are upgrading from an incompatible version
            # save preinit for rollback...
            mv $CF/sbin/preinit $CF/sbin/preinit.bak
        fi
        tar --unlink -zxpf $jboot -C $CF || fail=1
        restore_loader_tweaks

        # The boot package is used during rollback to restore the files
        # which exist outside the Junos ISO.
        # In dual root systems we do not need to save the boot package because
        # rollback is performed by switching the active slice. We can conserve
        # disk space by skipping the save.
        if [ ! "$ALT_ROOT_INSTALL" ]; then
            echo "Saving boot file package in /var/sw/pkg/$jboot"
            mkdir -p /var/sw/pkg
            cp $jboot /var/sw/pkg
        fi

        # the tar command does not fix the permissions of existing dirs
        chmod 1777 $CF/var/tmp
        chmod 0775 $CF/var/log

        # BIOS check for platforms that may need BIOS autoupgrade
        bios_check
    else
        # We must be transitioning to the new layout.
        # an extra reboot is required...
        mkdir -p $preinstall
        mv $jboot $preinstall
        cp ./+install.junos /packages/finish-install.jboot
        case `grep rtld= /etc/rc` in
        "") ;; # /etc/rc has been cleaned of the old 5.3 downgrade logic
        *)  # cause preinit to mount jbase on its alternative mount
            # else, /etc/rc will create this and reboot again.
            mkdir -p $pkgdir_mnt/jbase_mnt
            ;;
        esac
        echo 'autoboot_delay="2"' >> /boot/loader.conf
        warn Need to cleanup old jboot
        warn_of_reboot jboot
        warn The update process will automatically reboot again when done
        echo
    fi

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

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

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