#!/bin/sh
#
# $Id$
#
# Copyright (c) 2012, Juniper Networks, Inc.
# All rights reserved.
#
# JUNOS installation script for installation from loader.
#
# This script is executed when JUNOS installation is performed from loader
# prompt.
#
# Installation from loader formats the target media and installs JUNOS on it.
# This method does not depend on any existing contents of the router's storage
# media, so it can be used for:
#   1. Installing the first copy of JUNOS on a blank media.
#   2. Recovering a router whose internal media has corrupt file-system
#

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

# This script can be launched as the init process. In that case
# stdin/stdout/stderr are not connected - this code must be the first thing in
# this file, else the script will fail when it runs as init.
export EXPR_COMPAT=1
if [ ! "$initconsole" ] ; then
    export initconsole=YES
    # Start another instance of this script with stdin/out connected to console
    # Continuing to execute the script as init is not a good idea as any bug
    # in the script results in kernel panic - init died. Spawning a child
    # to do the real work allows the system to reboot gracefully in case of
    # failures and also allow error messages to appear on the console.
    exec settty /dev/console $0 "$@"
fi


# Creates the memory disk which will be the MFSROOT and mounts it
create_mfsroot_memdisk() {
    local md_disk

    md_disk=$(mdconfig -a -t malloc -s $MFSROOT_SIZE)
    newfs /dev/$md_disk
    mount /dev/$md_disk $MFSROOT_MOUNTPOINT
}


# Copy files from the disk to the MFSROOT, avoiding packages and devfs
populate_mfsroot() {
    mkdir "${MFSROOT_MOUNTPOINT}/cf"
    for cfdir in /cf/*
    do
        # Don't copy contents of packages, dev, boot and usr.
        case $cfdir in
        /cf/packages|/cf/dev|/cf/boot|/cf/usr) continue;;
        esac

        cp -Rp $cfdir "${MFSROOT_MOUNTPOINT}/cf"
    done

    # Create empty packages, dev, boot and usr directories on the MFSROOT
    mkdir -p "${MFSROOT_MOUNTPOINT}/cf/packages/mnt"
    mkdir "${MFSROOT_MOUNTPOINT}/cf/dev" "${MFSROOT_MOUNTPOINT}/cf/boot" "${MFSROOT_MOUNTPOINT}/cf/usr"

    # This is where the JUNOS ISO will be mounted on the MFSROOT
    mkdir $JUNOS_MOUNTPOINT
}


# A JUNOS root filesystem has symlinks at the top level pointing to contents
# in var. Make MFSROOT look like that.
populate_mfsroot_symlinks() {
    # To each directory under /cf, create a symlink to it in /
    cd $MFSROOT_MOUNTPOINT
    ln -s cf/* .

    # Except that usr and pkg in / should point to junos/*
    rm -f usr pkg
    ln -s junos/usr .
    ln -s junos/pkg .
}


# Make the packages from the disk visible in the MFSROOT and also mount devfs
# on it
setup_mfsroot_mounts() {
    # Packages directroy in MFSROOT should point to the one on the disk.
    # This is a read only mount.
    mount_nullfs /cf/packages "${MFSROOT_MOUNTPOINT}/cf/packages"

    # /dev on MFSROOT should have devfs mounted on it
    mount_devfs /dev "${MFSROOT_MOUNTPOINT}/dev"

    mount_nullfs /cf/usr "${MFSROOT_MOUNTPOINT}/cf/usr"
    mount_nullfs /cf/boot "${MFSROOT_MOUNTPOINT}/cf/boot"
}


# This is it, we are ready to fly...
boot_from_mfsroot() {
    cd /
    # MFSROOT is a memory disk which has been dressed up to look exactly
    # like the root filesystem in the disk.
    # We chroot into the MFSROOT and launch preinit and preinit will continue
    # bootup exactly as if we were booting off the secondary storage.
    # The exec is necessary so that preinit still finds itself with PID=1
    exec chroot /junos /sbin/preinit-main "$@"
    
    # Something went wrong - we aren't supposed to reach this line !!
    echo "Bootup from MFSROOT failed ..."
    # ... and therefore the init process exits sadly 
    exit 1
}


MFSROOT_MOUNTPOINT="/junos"
MFSROOT_SIZE="20M"
JUNOS_MOUNTPOINT="/junos/junos"

main() {
    # When MFSROOT is supported, original 'preinit' is renamed as 'preinit-main', 
    # and a new binary 'mfsinit' is copied as preinit. New 'preinit'(mfsinit) 
    # sets an enviromnet to run this script and execs. This script after successful
    # init, exces again 'preinit-main'. 

    # Consume the string meant for errnor notification
    err_str=$1
    shift
    if [ "$err_str" != "NULL" ]; then
        echo "MFSROOT:$err_str"
        # "mfsinit" failed, just continue with the normal root.
        exec /sbin/preinit-main
    fi
    # At least we reached here
    echo "Process-$$ beginning MFSROOT initialization..."

    echo "Creating MFSROOT..."
    create_mfsroot_memdisk

    echo "Populating MFSROOT..."
    populate_mfsroot

    echo "Creating symlinks..."
    populate_mfsroot_symlinks

    echo "Setting up mounts..."
    setup_mfsroot_mounts

    echo "Continuing boot from MFSROOT..."
    boot_from_mfsroot "$@"
}

main "$@"
