#!/bin/bash
#
# Startup script for spirit-xr platforms.
#
# This scripts run on all VMs so checks must be performed runtime.
# 
#
# Copyright (c) 2015-2017 by Cisco Systems, Inc.
# All rights reserved.
#

# Log all outputs
. /etc/init.d/logflow
logflowall

# source function library
. /etc/init.d/functions

# source spirit function library
. /etc/init.d/spirit-functions

# source PD-function library
. /etc/init.d/spirit_pd.sh

if [ -f /etc/init.d/app-hosting-functions ]; then
    . /etc/init.d/app-hosting-functions
fi

# Skip execution of this script for diag images
MFG_DIAG=`cat /proc/cmdline | grep MFG_DIAG=`
if [ -n "$MFG_DIAG" ]; then
     exit 0 
fi


# Extract boardtype from EFI or from command line
# Possible values are RP, LC, SC, XC or FC
get_board_type
if [ -z "$BOARDTYPE" ]; then
   BOARDTYPE="RP"
fi

CMDLINE_PLATFORM=`cat /proc/cmdline | sed 's/^.*platform=//' | cut -d" " -f1`
if [ "$CMDLINE_PLATFORM" == "xboard" ]; then
    if [ $(lspci -mm | grep -ic Marvell) -ne 0 ]; then
        PLATFORM="XMBOARD"
    else
        PLATFORM="XBOARD"
    fi 
elif [ "$CMDLINE_PLATFORM" == "forge" ]; then
    PLATFORM="FORGE"
elif [ "$CMDLINE_PLATFORM" == "fretta" ]; then
    PLATFORM="fretta"
elif [ "$CMDLINE_PLATFORM" == "zermatt" ]; then
    PLATFORM="zermatt"
else
    PLATFORM="OTHER"
fi

VMTYPE=`cat /proc/cmdline | grep vmtype=`
if [ -n "$VMTYPE" ]; then
   VMTYPE=`cat /proc/cmdline | sed 's/^.*vmtype=//' | cut -d" " -f1`
fi
if [ -z "$VMTYPE" ]; then
   VMTYPE=hostos
fi


# For LXC platforms set the inotify ceiling in the host. It applies
# to all guests.
if [ "$VMTYPE" = "hostos" ]; then
    if [ "$VIRT_METHOD" = "lxc" ]; then
        echo 8192 > /proc/sys/fs/inotify/max_user_instances
    fi
fi

# Set CFS Parameters for Admin VM & XR VMs
set_sched_param () {
    # The model name is QEMU on simulated hosts.
    QEMU=`grep QEMU /proc/cpuinfo | wc -l`
    nproc=`grep processor /proc/cpuinfo | wc -l`
    # if not VXR simulation, or if nprocessors > 1, then...
    if [ $QEMU -eq 0 -o $nproc -gt 1 ] ; then
        mount -t debugfs none /sys/kernel/debug 2> /dev/null
        echo NO_WAKEUP_PREEMPTION > /sys/kernel/debug/sched_features

        sysctl -w kernel.sched_min_granularity_ns=4000000 >/dev/null 2>&1
    fi
}


# Put a dummy implementation of lsusb for non-host VM
dummy_lsusb () {
    # usb on vm is a virtio-blk-pci device. lsusb is not needed.
    cat << EOF > /usr/sbin/lsusb
#!/bin/bash
echo lsusb not supported. 1>&2
exit 1
EOF
}

enable_kernel_ftrace () {
    if [ ! -x /usr/bin/trace-cmd ]; then
        return 1 
    fi
    if [ "$VMTYPE" = "hostos" ]; then
        BUFFER_SIZE=1024
    else
        BUFFER_SIZE=2560
    fi
    echo $BUFFER_SIZE > /sys/kernel/debug/tracing/buffer_size_kb
    # Set trace clock global to order events across CPUs
    echo "global" > /sys/kernel/debug/tracing/trace_clock

    trace-cmd start -e raw_syscalls -e irq_handler_entry \
        -e irq_handler_exit -e softirq_entry -e softirq_exit \
        -e sched_switch -e sched_wakeup -e sched_wakeup_new \
            1>/dev/null 2>&1
}

spirit_start () {
   # Run this script only once for the lifetime of the VM/LXC
   # unless the script is stopped and started.
   [ -f /var/lock/subsys/spirit ] && exit 0

   # Check to see if this is a ramfs image (meaning it is an install image)
   # used for preparing the boot partitions. If it is skip the reminder of
   # this script.
   INSTALLCHK=`cat /proc/cmdline | grep install=`
   if [ -z "$INSTALLCHK" ]; then
       echo -n $"Starting programs for ${BOARDTYPE} on ${VMTYPE}: "
       success
       echo

       if [ "$VMTYPE" = "hostos" -a "$VIRT_METHOD" = "lxc" ]; then
           sysctl -w kernel.sched_latency_ns=20000000
           sysctl -w kernel.sched_min_granularity_ns=4000000
           echo NO_WAKEUP_PREEMPTION > /sys/kernel/debug/sched_features
           echo NO_GENTLE_FAIR_SLEEPERS > /sys/kernel/debug/sched_features
       fi

       if [ "$VMTYPE" != "hostos" ]; then
           if [ "$VIRT_METHOD" = "vm" ]; then
               # Set CFS Parameters
               set_sched_param

               # put in a dummy implementation of lsusb
               dummy_lsusb 
           fi

       fi

       if [ "$VIRT_METHOD" = "vm" ]; then
           enable_kernel_ftrace
           # Treat oops as panic common for host and vms
           echo 1 > /proc/sys/kernel/panic_on_oops 
       fi

       # Invoke any platform specific configuration
       platform_specific_configuration $VMTYPE $VIRT_METHOD $CMDLINE_PLATFORM
       platform_load_kernel_module  $VMTYPE $VIRT_METHOD $CMDLINE_PLATFORM

       # Add a cron job to monitor and clean up tmp directory
       cp /etc/tmpdir_cleanup.crontab /etc/cron.d/

       if [ "$VMTYPE" = "hostos" ]; then
           #Create ssh keys
           if [ ! -s /root/.ssh/id_rsa ]; then
               # File may exist and be 0-length - in which case, 
               # ssh-keygen run from script won't remove the existing file.
               # So, explicitly remove and regenerate keys
               if [ -f /root/.ssh/id_rsa ] ; then
                   rm -f /root/.ssh/id_rsa
               fi

               ssh-keygen -q -t rsa -f /root/.ssh/id_rsa                \
                   -C root@host -N '' > /dev/null 2>&1
           fi 


           # Launch admin-vm for all platforms except Forge
           if [ "${PLATFORM}" != "FORGE" ]; then

               # Launch admin-vm only if conditions are met
               
               calvados_launch_check
               ret=$?
               if [ "$ret" = "0" ]; then
                   if [ -d /dev/udrv_hwid ]; then
                       rm -rf /dev/udrv_hwid
                   fi
                   mkdir /dev/udrv_hwid

                   # This is an upstart event for admin-vm to launch
                   
                   if [ ${PLATFORM} != "fretta" -a  ${PLATFORM} != "zermatt" ]; then
                       initctl emit start-udrv-hwid-client
                   fi
                   initctl emit start-calvados
                   initctl emit hushd-start

                   # pd_notify_sysadmin_vm_started is necessary only for some
                   # platforms that need to track HOST events
                   declare -F pd_notify_sysadmin_vm_started && pd_notify_sysadmin_vm_started
               fi
           else
               # Handle launch of VMs specific to Forge
               if [ -f /usr/bin/forge_xr_vm_launch.sh ]; then
                   bash /usr/bin/forge_calvados_vm_launch.sh
                   bash /usr/bin/forge_xr_vm_launch.sh
               fi
           fi
       fi  #host-os

       # If running within sysadmin-vm, startup calvados processes
       if [ "$VMTYPE" = "sysadmin-vm" ]; then
           # if the file was not created during pxe boot, then
           # create one. Perhaps the system was SU from an
           # older release
           if [ ! -f $PD_BOARD_INST_CONF ]; then
               local PI_CARDTYPE=UNKNOWN
               source $INSTALL_PARAMS_OVERRIDE $PD_BOOTSTRAP           \
                   1 $BOARDTYPE $PI_CARDTYPE $PD_BOARD_INST_CONF
           fi

           # To block few calvados processes
           if [ "$CMDLINE_PLATFORM" == "ncs1k" ] || [ "$CMDLINE_PLATFORM" == "ncs1001" ]; then
               find /opt/cisco/calvados -name  "craft_mgr_rp.startup" | xargs rm
           fi

           if [ -f /opt/cisco/calvados/bin/calvados_startup.sh ]; then
               /opt/cisco/calvados/bin/calvados_startup.sh &

               # pd_notify_sysadmin_vm_init_done is necessary only for some
               # platforms that need to track SysAdmin VM init events
               
               declare -F pd_notify_sysadmin_vm_init_done &>/dev/null && \
                   pd_notify_sysadmin_vm_init_done
           else
               # Cannot find calvados_startup.sh script, a possible install
               # issue, so notify PD code about this fatal failure so a
               # reimage can be triggered
               declare -F pd_notify_sysadmin_vm_init_failed &>/dev/null && \
                    pd_notify_sysadmin_vm_init_failed \
"Cannot find /opt/cisco/calvados/bin/calvados_startup.sh script"
           fi
       fi

       # If running within xr-vm, startup XR processes
       if [ "$VMTYPE" = "xr-vm" ]; then
           # Create ssh keys
           if [ ! -s /root/.ssh/id_rsa ]; then
               # File may exist and be 0-length - in which case, 
               # ssh-keygen run from script won't remove the existing file.
               if [ -f /root/.ssh/id_rsa ] ; then
                   rm -f /root/.ssh/id_rsa
               fi
               ssh-keygen -q -t rsa -f /root/.ssh/id_rsa               \
                   -C root@XR -N '' > /dev/null 2>&1

           fi

           if [[ "$VIRT_METHOD" == "vm" ]]; then
               declare -F app_host_is_enabled &>/dev/null && app_host_is_enabled
               if [[ $? -eq 0 ]]; then
                   # Do additional app-hosting pre-setup for KVM virt-method.
                   # This corresponds to similar LXC logic in xr_pre_launch.sh
                   [ -d /misc/app_host ] && ln -sf /misc/app_host /apphost:
                   create_global_vrf_dirs
                   create_user_scratch_space
               fi
           fi

           # Kick start XR processes
           [ -f /pkg/etc/xr_startup.sh ] && /pkg/etc/xr_startup.sh &
           proc_id=$!
           if [ "$CMDLINE_PLATFORM" == "ncs1k" ] || [ "$CMDLINE_PLATFORM" == "ncs1001" ]; then
               wait $proc_id
           fi
       fi
   else
       echo -n $"programs are not started for install image: "
       success
       echo 
   fi

   # create a lock file
   touch /var/lock/subsys/spirit
}

case "$1" in
  start)
	spirit_start
	;;
  stop)
    # If host then wait for calvados to go down
    if [ "$VMTYPE" = "hostos" ]; then
        RUNNING_VM=`virsh list | grep -E running | grep "sysadmin" | awk -F" " '{ print $2 }'` > /dev/null 2>&1
        if [ "${RUNNING_VM}" != "" ]; then
            for i in {1..10} ; do
                STATE=`virsh domstate ${RUNNING_VM}`
                if [ "$STATE" == "shut off" ]; then
                    break
                else
                    sleep 1
                fi
            done
        fi
    fi

	echo -n $"Stopping programs for ${BOARDTYPE} on ${VMTYPE}: "
	success
	if [ "$VMTYPE" = "xr-vm" ]; then
	    echo -n "Waiting processmgr to shutdown"
	    while [ "`pidof processmgr`" != '' ]; do
		echo -n "."
		kill -KILL `pidiof processmgr` 2> /dev/null
		sleep 0.1
	    done
	    success
	    echo -n "Sending NSR processes the KILL signal..."
	    for nsr_proc in 'tcp' 'mpls_ldp' 'bgp' 'msdp';
	    do
		if [ "`pidof $nsr_proc`" != '' ]; then
		    echo -n " "\'$nsr_proc\' "pid:"`pidof $nsr_proc`;
		    kill -KILL `pidof $nsr_proc`;
		fi
	    done
	    success
	fi
	echo
	[ -r /var/lock/subsys/spirit ] || exit 3
	rm /var/lock/subsys/spirit
	;;
  restart)
	$0 stop
	$0 start
	exit $?
	;;
  reload)
        $0 start
	exit $?
	;;
  *)
	echo $"Usage: $0 {start|stop|restart|reload|status}"
	exit 2
esac

exit 0
