#!/sbin/sh

# $Id: mdimage-prepare.sh 493955 2012-01-31 04:15:37Z ib-builder $

# Copyright (c) 2009, Juniper Networks, Inc.
# All rights reserved.

# Script for common preparations before zeroize and repartition.
#
# This script will be called by the mdimage-startup script if the 
# specified operation requires this common preparation.


# Tunable constants
MFS_SIZE_MB=1
KMEM_MARGIN_MB=10
MDIMAGE_OPERATION_LOG_FILE="/tmp/mdimage-op.log"

LOG_FILE=/dev/null 


# Signals are already disabled in mdimage-startup, so we do not disable
# here again.


exit_cleanup() 
{
    # Save the log to CF (and memory disk too - as we will restore from here)
    echo "Saving logs"
    
    # If CF was mounted, append the logs to the partition-cf logs.
    if [ -f /a/cf/var/log/mdimage-op.log ]; then
        cat $MDIMAGE_OPERATION_LOG_FILE >> /a/cf/var/log/mdimage-op.log
        mv /a/cf/var/log/mdimage-op.log $MDIMAGE_OPERATION_LOG_FILE
    fi

    cp $MDIMAGE_OPERATION_LOG_FILE /a/cf/var/log
    cp $MDIMAGE_OPERATION_LOG_FILE /mnt/cf/var/log

    # Unmount all partitions mounted from any physical media
    echo "Unmounting all media"
    umount /a
    umount /e
}


critical()
{
    {
        echo "\$ $@"
        eval "$@"
        status=$?

        if [ "$status" != "0" ]; then
            echo "ERROR: $status: Failure encountered."
        else
            echo "Status OK"
        fi
        
        echo ""

    }  >> $LOG_FILE 2>&1

    if [ "$status" != 0 ]; then
        # Do the cleanup steps before exiting
        echo "Preparation phase failed"
        exit_cleanup
        exit 1
    fi
} 


log_command()
{
    {
        echo "\$ $@"
        $@
        echo ""
    }  >> $LOG_FILE 2>&1
} 



# Starting message
echo "Starting preparation phase"

# Create and mount a small mfs on /mfs
critical mdmfs -M -s ${MFS_SIZE_MB}M md /mfs
critical mkdir /mfs/tmp

# Now that tmp area is setup, start logging to a log file
LOG_FILE=$MDIMAGE_OPERATION_LOG_FILE

# First work out what media we have
# mdimage-startup should have set DEV by now
for DEV in $DEV /dev/ad?s1a
do
    [ -c $DEV ] || continue
    # Mount CF root and config 
    critical mount $DEV /a
    $SKIP_ZEROIZE critical mount ${DEV%a}e /e
    break
done

# Get free kernel mem
kmem_free_b=$(sysctl -n vm.kmem_map_free)

# Get available kernel mem in 512 byte blocks:
# Leave some margin in kernel mem and use the rest
kmem_avail_512b=$(expr \( $kmem_free_b - \( $KMEM_MARGIN_MB \* 1024 \* 1024 \) \) / 512 )

# Size to reserve for memory device (in 512b sectors):
# The final size has to be cylinder aligned according to the disk geometry.
# The geometry for memory disk is 16065 sectors per cylinder 
# (255 Heads x 63 Sectors/Track).
# So we round off to multiple of 16065 sectors plus 10 extra.
# Why 10 extra? fdisk does not include the last cylinder otherwise.
mem_disk_size_512b=$(expr \( $kmem_avail_512b \/ 16065 \) \* 16065 \+ 10)


# Create memory disk for CF backup
echo "Available kernel memory: $kmem_free_b"
echo "Creating memory disk: $mem_disk_size_512b sectors"
mem_disk_name=$(mdconfig -a -t malloc -o reserve -s $mem_disk_size_512b)

if [ "$mem_disk_name" = "" ]; then
    echo "Memory disk creation failure"
    exit 1
fi


# Run fdisk on memory disk to create a slice
critical fdisk -I -b /a/cf/boot/mbr /dev/$mem_disk_name


# Decide fraction for root partition based on product model and CF size
flash_size_mb="$(bsdlabel -A ${DEV%a} | awk '/bytes\/sector/ { bps=$2; } /sectors\/unit/ { spu=$2; } END { printf "%d\n",  bps * spu / 1024 /1024 }')"

if [ $flash_size_mb -le 256 ]; then
    # 96 % for small CF
    fraction=96
else
    fraction=90
fi
md_root_size_512b=$(expr $mem_disk_size_512b \* ${fraction:-90} \/ 100)

# Run bsdlabel on memory disk to create root and config partitions
label_file="/tmp/bsdlabel.new"
rm $label_file > /dev/null 2>&1
{
    echo " a: $md_root_size_512b    *   unused  0  0"
    echo " c: *                     *   unused  0  0"
    echo " e: *                     *   unused  0  0" 
} >> $label_file

log_command bsdlabel -Rn /dev/${mem_disk_name}s1 $label_file
critical bsdlabel -R /dev/${mem_disk_name}s1 $label_file

# Create filesystems on the new root and config partitions in the memory disk
critical newfs /dev/${mem_disk_name}s1a
critical newfs /dev/${mem_disk_name}s1e

# Mount the in-memory root partition at /mnt
critical mount /dev/${mem_disk_name}s1a /mnt

# Start preparing a JUNOS root under /mnt

# Copy CF root partition to the in-memory root partition
echo "Backing up root filesystem... (this may take a few minutes)"
critical cp -Rpv /a/* /mnt

# Mount the Junos ISO which is in memory under /mnt/junos
mem_disk_name_junos=$(mdconfig -a -t vnode -o jcompress -o readonly -JO -f /mnt/packages/junos)
if [ "$mem_disk_name_junos" = "" ]; then
    echo "Memory disk creation failure"
    exit 1
fi
critical mount -t cd9660 -r /dev/$mem_disk_name_junos /mnt/junos

# Create fstab.mr in the memory disk - replace /dev/md0 with junos memory disk
for f in fstab.mr fstab.chroot
do
    [ -s /a/etc/$f ] || continue
    cat /a/etc/$f |
    sed -e "s/\/dev\/md0/\/dev\/$mem_disk_name_junos/" > /mnt/etc/$f
    break
done

# Mount loopback /mnt/cf in /mnt/junos/cf
critical mount_nullfs /mnt/cf /mnt/junos/cf

# Mount devfs in /mnt/junos/dev
critical mount_devfs devfs /mnt/junos/dev

# Mount in-memory config in /mnt/junos/config
critical mount /dev/${mem_disk_name}s1e /mnt/junos/config

# Create mfs to mount under /mnt/junos/mfs
critical mdmfs -M -s ${MFS_SIZE_MB}M md /mnt/junos/mfs
critical mkdir -p /mnt/junos/mfs/tmp /mnt/junos/mfs/var/etc /mnt/junos/mfs/var/run

# Create boot device softlinks in /dev - These should point to the memory disk
critical ln -s  ${mem_disk_name}s1a /mnt/junos/dev/bo0s1a
critical ln -s  ${mem_disk_name}s1c /mnt/junos/dev/bo0s1c
critical ln -s  ${mem_disk_name}s1e /mnt/junos/dev/bo0s1e

if [ -z $SKIP_ZEROIZE ]; then
    # Copy CF config partition to the in-memory config partition
    echo "Backing up configurations"
    critical cp -Rpv /e/* /mnt/junos/config
    # Do the final exit cleanups
    exit_cleanup
else
    # for zeroize this is all we need
    echo "Unmounting all media"
    umount /a
fi

echo "Preparation phase completed successfully"


# The router is now levitating in RAM, no longer bound to any physical media :)
#
# We have a proper JUNOS root set up in RAM under /mnt with the 
# JUNOS ISO from /mnt mounted under /mnt/junos.
# The mfs, dev, config and cf mounts on the JUNOS tree are also complete.
#
# So once chrooted into /mnt/junos, everything should work just as in normal
# mode.
#
# Since no physical media is mounted, we should be able to operate on any media.

