#!/bin/bash
#########################################################################
#                                                                       #
# Name          : rcS                                                   #
# Purpose       : Run config, single user, executed from inittab        #
#                                                                       #
#########################################################################

# -----------------------------------------------------------------------------
# main script starts here
# -----------------------------------------------------------------------------

# pick up some helper functions
source /ciena/scripts/utils.sh
source /ciena/scripts/saos_utils.sh
source /ciena/scripts/fault.sh
source /ciena/scripts/board_lib.sh

family=$(cat /family)
model=$(get_board_name_pretty)

# Mount the directory tree located in /etc as a tmpfs filesystem on top of
# the read-only /etc directory (borrowed from CNX fsperm script).
/bin/tar czf /tmp/etc.tar.gz -C / etc/*
/bin/mount /etc
/bin/tar xzf /tmp/etc.tar.gz -C /
chmod o-w /etc
# Store this so we have access to items in the original etc dir
/bin/mv -f /tmp/etc.tar.gz /etc/etc.tar.gz

# Populate ld.so.cache so that shared libs can be found in unconventional paths.
/sbin/ldconfig

# prevent init failures from calling exit
EXIT_OVERRIDE="echo -e \"continuing after failure\""

VERSION_FILE=/mnt/apps/version

if [ -f "$VERSION_FILE" ] ; then
    version="$(cat $VERSION_FILE)"
else
    version="<no-version>"
fi

CONSOLE_TTY=$(get_console_tty)

# Display a banner directly to the serial port
# (this will be seen even if the console is disabled)
/ciena/scripts/print_banner "$version" > $CONSOLE_TTY

print_app_line_cr
print_app_line_cr "$family $model (rootfs $version)"
print_app_line_cr

# Make tmpfs directories that various things expect to find
mkdir -p -m 0775 /tmp/fifo/mon /tmp/log /var/db /var/log /var/run /tmp/users
mkdir -p -m 0755 /tmp/bin
mkdir -p -m 0640 /var/run/sshd
mkdir -p -m 1777 /tmp/fifo/leos

# Create the root user home directory
roothomedir="$(cat /etc/passwd | grep ^root: | cut -d: -f6)"
mkdir -p -m 0700 $roothomedir

# Create well-known pipes
/bin/mknod -m 0200 /tmp/fifo/mon/leos p

# For re-branding (hiding mentions of "leos" during normal runs)
ln -s /tmp/fifo/mon/leos        /tmp/fifo/mon/saos

# All console output will be sent to the CONSOLE_COLLECTOR.  This pipe is sent
# to the CONSOLE_MIRROR, which logs all console output.  The CONSOLE_OUT pipe
# is used echo console output to the serial port (if enabled).
#
CONSOLE_COLLECTOR=/tmp/log/console_collector
CONSOLE_MIRROR=/tmp/log/console_mirror
CONSOLE_OUT=/tmp/log/console_out

/bin/mknod $CONSOLE_COLLECTOR p
/bin/mknod $CONSOLE_MIRROR    p

# Use the logger utility to read from the CONSOLE_MIRROR pipe
# (this will send all things written to CONSOLE_MIRROR into syslog)
/bin/cat <$CONSOLE_MIRROR | /usr/bin/logger -t console &

# If the kernel has the console argument on the command line, then we are
# interested in seeing debug output on the serial port.
if console_enabled; then
    /bin/mknod $CONSOLE_OUT p
    # Use cat to read from the CONSOLE_OUT pipe.  This will send all things
    # written to CONSOLE_OUT to the current stdout (should be the serial port).
    /bin/cat <$CONSOLE_OUT &

    # Glue the CONSOLE_COLLECTOR to feed both CONSOLE_MIRROR and CONSOLE_OUT
    /usr/bin/tee -i $CONSOLE_MIRROR >$CONSOLE_OUT <$CONSOLE_COLLECTOR &
else
    # Only send console output to the logging system
    /bin/cat $CONSOLE_COLLECTOR >$CONSOLE_MIRROR &

    # Provide some notification that we are running rcS
    echo -en "Initializing " > $CONSOLE_TTY
    while :; do
        sleep 3
        echo -n "." > $CONSOLE_TTY
    done &
    sleeping_dots=$!
fi

# Glue stdout and stderr to CONSOLE_COLLECTOR
exec &>$CONSOLE_COLLECTOR

fg_run "tuning kernel parameters" /sbin/sysctl -q -p

if [ -r "/efence_build" ] ; then
    max_map_count=131072
    fg_run "EFENCE, vm.max_map_count=$max_map_count" \
        /sbin/sysctl -q -w vm.max_map_count=$max_map_count
fi

# Set the kernel log level to exclude NOTICE, INFO and DEBUG.
# This will be adjusted later based on the krn settings.
fg_run "setting kernel output to 4" /bin/dmesg -n 4

# Configure core dump system.
fg_run "enabling core file generation" ulimit -c unlimited

# The LINX module will get autoloaded by the userspace library if required.
# It is manually loaded here so that module parameters can be provided, so
# this must be done before running any executables that will try to use LINX.
insmod_wrapper linx linx_max_tmorefs=2048 linx_mem_fragmentation=yes

fg_run "setup evt shared memory" /ciena/bin/evt_setup init
fg_run "setup evt ram0 log"      /ciena/bin/evt_setup ram0 1000
fg_run "setup evt ram1 log"      /ciena/bin/evt_setup ram1 500
fg_run "setup evt ram2 log"      /ciena/bin/evt_setup ram2 500
fg_run "setup evt ram3 log"      /ciena/bin/evt_setup ram3 100

bg_run_and_wait "starting signal_catcher" /ciena/bin/signal_catcher

bg_run_and_wait "starting evt_syslog"     /ciena/bin/evt_syslogd
bg_run_and_wait "starting evt_klog"       /ciena/bin/evt_klogd

set_epoch_time 200001010000

REMOTE_IFNAME=remote
LOCAL_IFNAME=local
L3_IFNAME=saosL3
AV_TITAN_IFNAME=avTitan

KRN_CONF=/mnt/sysfs/system/krn.conf

# rootfs_location should be one of {nfs,initramfs,flash}
# rootfs_rw       should be one of {writable,read-only}
rootfs_location=$(get_rootfs_location)
rootfs_rw=$(get_rootfs_rw)

get_running_bank
case "$?" in
    $EXIT_BANKA) rootfs_bank="A" ;;
    $EXIT_BANKB) rootfs_bank="B" ;;
    *)           rootfs_bank=""  ;;
esac

print_app_line_cr
print_app_line_cr "rootfs is $rootfs_rw from $rootfs_location $rootfs_bank"
print_app_line_cr

# umask needed for permissions on new jffs2 mount points
umask 0002

case "$rootfs_location" in

    initramfs)
        print_app_line_cr "sysfs from ram"
        ;;

    nfs)
        enable_fpga_flash_driver

        # Mount the directory tree located in /mnt/sysfs as a tmpfs filesystem
        # on top of the RO /mnt/sysfs directory (borrowed from CNX fsperm
        # script).
        /bin/tar cf /tmp/sysfs.tar -C / mnt/sysfs/*
        fg_run "mount sysfs to ram" /bin/mount -t tmpfs -o rw tmpfs /mnt/sysfs
        /bin/tar xf /tmp/sysfs.tar -C /
        /bin/rm /tmp/sysfs.tar
        fg_run "mount logs to ram" /bin/mount -t tmpfs -o rw tmpfs /mnt/log
        if xftp_partition_supported; then
            fg_run "mount xftp to ram" /bin/mount -t tmpfs -o rw tmpfs /mnt/xftp
        fi

        print_app_line "fix up le0.conf"
        /ciena/scripts/write_nfs_le0_conf > /mnt/sysfs/system/le0.conf
        print_result "$?"

        print_app_line "enable root access"
        /bin/touch /mnt/sysfs/system/enableRoot
        print_result "$?"

        print_app_line "remove /etc/securetty"
        /bin/rm -f /etc/securetty
        print_result "$?"
        ;;

    flash)
        enable_fpga_flash_driver
        fg_run "mount sysfs via fstab" /bin/mount /mnt/sysfs

        # allocate/mount xftp before the log partition so that xftp
        # gets priority when allocating free space.
        if xftp_partition_supported; then
            fg_run "mount xftp partition" mount_xftp_partition
        fi

        mount_log_partition

        if mount_kernel; then
            fg_run "mount kernel bank A" /bin/mount /mnt/kernelA
            fg_run "mount kernel bank B" /bin/mount /mnt/kernelB
        fi
        fg_run "mount image bank A"  /bin/mount /mnt/imageA
        fg_run "mount image bank B"  /bin/mount /mnt/imageB

        MANIFEST_RESULT_FILE=/tmp/MANIFEST_RESULT.$$
        MANIFEST_OUTPUT=/tmp/MANIFEST_OUTPUT.$$
        print_app_line_cr "start manifest check (sha256sum)"
        (
            # Run the manifest check on the image mount point (rather than /)
            # so that changes to files in tmpfs overlays (such as /etc) can
            # proceed while we are running this check.
            #
            cd /mnt/image$rootfs_bank
            /usr/bin/sha256sum -c MANIFEST_SHA256 &> $MANIFEST_OUTPUT
            echo -n "$?" > $MANIFEST_RESULT_FILE
        ) &
        MANIFEST_PID=$!

        check_reset_to_factory_defaults
        set_local_interface_mac
        ;;

    *)
        print_app_line_cr "no handling for rootfs in $rootfs_location"
        ;;
esac

# create the directory that the evt logs will reside in
# ensure that permissions are correct
# create softlink for evt logs
mkdir -p /mnt/log/evt
chmod 0777 /mnt/log/evt
ln -s /mnt/log/evt /var/log/evt

# link the expected core file location to the actual location
mkdir -p -m 0775 /mnt/log/corefiles
chmod 0775 /mnt/log/corefiles
ln -s /mnt/log/corefiles /tmp/corefiles

# This must be done after /var/log/evt is setup
fg_run "setup evt flash0 log"      /ciena/bin/evt_setup flash0 25
fg_run "setup evt flash1 log"      /ciena/bin/evt_setup flash1 50
fg_run "setup evt exception log"   /ciena/bin/evt_setup except

# verify that a power fail was actually a power fail
verify_reset_reason

# This must be done after the evt exception log is initialized
if [ "$rootfs_location" == "flash" ] ; then
    # only need to look at cookies on flash boot
    capture_reboot_cookie
fi

# The rc.guardian script requires cookie access to be working.
# The guardian can only be started after the watchdog device is available
# The parameter provided here is the number of seconds that the system has
# before calling guardian run (the guardian will reboot the system if the
# init phase takes longer than this).
/etc/init.d/rc.guardian init 360

# Did the bootloader swap banks on us?
# This check needs to be before board support FPGA update and user preloader
# update because they will update the preferred bank if it is different from 
# the running bank.
if [ "$rootfs_location" = "flash" ]; then
    get_running_bank
    running=$?
    get_preferred_bank
    preferred=$?
    if [ $running != $preferred ]; then
        /ciena/bin/evt_log ALERT "Flash bank swap occurred"
    fi
fi

if [ -x /ciena/scripts/boardsupport_update.sh ] ; then
    print_app_line_cr "Checking Board Support FPGA" 
    /ciena/scripts/boardsupport_update.sh
fi

# Check bootjumper
if ! spiboot_supported -a [ -x /ciena/scripts/update_bootjumper ] ; then
    fg_run_no_output "check bootjumper" \
        /ciena/scripts/update_bootjumper --if-blacklisted --no-prompt
fi

# Check preloader
if board_has_fpga_preloader && [ "$rootfs_location" == "flash" ] ; then
    fg_run_no_output "check preloader-user" \
        /ciena/scripts/update_fpga_preloader --bank user --compare 
    if [ "$?" -ne "0" ] ; then 
        fg_run_no_output "update preloader-user" \
        /ciena/scripts/update_fpga_preloader \
            --bank user --no-prompt
        spiboot_bank_set_to_running
        /ciena/scripts/bsf_upgrade.sh -r
    fi
    fg_run_no_output "check preloader-gold" \
        /ciena/scripts/update_fpga_preloader \
        --bank golden --if-blacklisted --no-prompt
fi

# Assign an address to the loopback device.
fg_run "assign IP address to loopback device" /sbin/ifconfig lo 127.0.0.1 up

# PWE mgmt link setup on 3932 board
setup_pwe

# Any user-installed pre-rc hook?
# These hooks are required because this rcS is on a read-only filesystem.
# We source it so that it can affect environment variables.
if [ -x /mnt/sysfs/system/prercS ] ; then
    fg_run "source /mnt/sysfs/system/prercS" source /mnt/sysfs/system/prercS
fi

# load krn settings
source /ciena/scripts/krn getenv

if [ "$KRN_CONSOLE" = "debug" ]; then
    # allow all kernel logs to appear on the console
    KLOG_LEVEL=7
else
    # prevent the kernel from logging to the console (except for kernel panic)
    KLOG_LEVEL=1
fi
fg_run "setting kernel output to $KLOG_LEVEL" /bin/dmesg -n $KLOG_LEVEL

initialize_fault_log
chmod 0775 $FAULTDIR

# retrieve any kernel panic logs from the pstore
handle_kernel_paniclog

# If we started a manifest check, wait for the result.
if [ -n "$MANIFEST_PID" ] ; then

    print_app_line "waiting for manifest check"
    wait $MANIFEST_PID
    MANIFEST_RESULT=$(cat $MANIFEST_RESULT_FILE)
    rm $MANIFEST_RESULT_FILE
    print_result "$MANIFEST_RESULT"
    
    # check if we need to force a reboot due to corrupted files
    if [ "$MANIFEST_RESULT" -ne "0" ] ; then

        log_message="file manifest integrity check failed, first was "
        log_message+="$(grep -v OK $MANIFEST_OUTPUT | head -n1)"
        /ciena/bin/evt_log ALERT $log_message

        # output a summary of failed files to the console
        grep -v OK $MANIFEST_OUTPUT

        # force a reboot unless we are in a debug mode
        if [ "$KRN_AUTO" != "disable" -a "$KRN_MODE" != "debug" ] ; then
            reboot          # To (presumably) alternate flash bank.
        fi
    else
        # remove the output file if no errors were detected
        rm $MANIFEST_OUTPUT
    fi
fi

# Make sure there's already a utmp file.  Telnet won't create one,
# though it will write to one that is there.
/bin/touch /var/run/utmp
/bin/touch /var/log/wtmp

# Initial configuration of telnet server.  Enabled when in debug mode.
if [ "$KRN_MODE" = "debug" ]; then
    /ciena/scripts/enable_telnet_debug
fi

# Initialize IPMI and set up comms to BMC for 3938
ipmi_port_init

# Export environment variables
source /etc/profile

dataplane_fpga_init

mgmt_interface_reset

# skyfall (3938) startup
skyfall_startup

insmod_wrapper uio_bcm_xgs_pci
insmod_board_specific

fg_run "Creating Remote Management interface" tunctl -f /dev/net/tun -t $REMOTE_IFNAME > /dev/null

fg_run "Creating L3 interface" tunctl -f /dev/net/tun -t $L3_IFNAME > /dev/null

fg_run "Creating Titan interface" tunctl -f /dev/net/tun -t $AV_TITAN_IFNAME > /dev/null
ip link set avTitan up

fg_run "Fixing /etc/issue" /ciena/scripts/fixup_etc_issue

# We're mistrustful of junk that may persist wrongly in sysfs, try
# to clean up ownership, which will let the permission cleanup work.
find /mnt/sysfs -type d -a ! \( -user root -a -group root \) | xargs -r chown root:root

# Ensure LE-OS su/gss users (group root members) have rooty goodness.
# (only run this on writable parts of the filesystem)
# Don't touch the seclog files, or the containing directory.  (JE-51679)
find /mnt/sysfs /tmp /etc \
   -xdev \
   -user root -group root \
   -path /mnt/sysfs/seclog -prune -o \
   ! -path /mnt/sysfs/seclog \
   ! -path /tmp/bin \
   ! -path /tmp/fifo/mon/leos \
   \( \( -perm -u=r -a \! -perm -g=r \) -o \( -perm -u=w -a \! -perm -g=w \) -o \( -perm -u=x -a \! -perm -g=x \) -o \
      \( -perm -g=r -a \! -perm -u=r \) -o \( -perm -g=w -a \! -perm -u=w \) -o \( -perm -g=x -a \! -perm -u=x \) \) \
    -print | xargs -r chmod g=u 2>/dev/null

# Make sure the root user homedir permission is still 0700
chmod 700 $roothomedir

# Force no group/other write on path to /mnt/sysfs/ssh/users
# so public key encryption works in strict mode. (JE-52370)
# This may be changed by the find above or may already be this way
# due to older software. No point in skipping it in the find above since
# - that would slow the find
# - we still have to force it here.
mkdir -p /mnt/sysfs/ssh/users /mnt/sysfs/cert/supp
chmod go-w /mnt/sysfs
chmod go-w /mnt/sysfs/ssh
chmod go-w /mnt/sysfs/ssh/users
chmod go-w -R /mnt/sysfs/cert
chmod go-r -R /mnt/sysfs/cert/supp


fg_run "Create time zone database" /ciena/scripts/gen_timezone_db

# Enable ICMP secure redirects.  Redirects are only accepted from known gateways
find /proc/sys/net/ipv4/conf -name secure_redirects -exec bash -c 'echo 1 >> {}' \;

# Disable ICMP accept-redirects.  The following is done programmatically by SAOS. Set to disabled by default.
find /proc/sys/net/ipv4/conf -name accept_redirects -exec bash -c 'echo 0 >> {}' \;
find /proc/sys/net/ipv6/conf -name accept_redirects -exec bash -c 'echo 0 >> {}' \;

# Disable ICMP send-redirects.  Only used if device behaves as L3 router with /proc/sys/net/ipv4/ip_forward.
find /proc/sys/net/ipv4/conf -name send_redirects -exec bash -c 'echo 0 >> {}' \;

# Any user-installed post-rc hook?  The very last thing we do if so.
# These hooks are required because this rcS is on a read-only filesystem.
if [ -x /mnt/sysfs/system/postrcS ] ; then
    fg_run "run /mnt/sysfs/system/postrcS" /mnt/sysfs/system/postrcS
fi

# Kill the background dot printer if it exists, and force a new line.
if [ -n "$sleeping_dots" ] ; then
    kill $sleeping_dots
    echo "." > $CONSOLE_TTY 
fi

# Turn on GRSEC enforcing if the system is in enhanced security mode
saparam read $ParamType_SecurityMode &> /dev/null
if [ "$?" -eq "0" ] ; then
    chgrp 500 /mnt/sysfs/config
    chgrp 500 /mnt/sysfs/archive
    chmod 1777 /mnt/log/evt
    print_app_line_cr "Enabling enhanced security enforcement"
    /sbin/gradm -E &> /dev/null
    if [ "$?" -ne "0" ] ; then
      print_app_line_cr "*** FAILED to enable enhanced security enforcement"
      print_app_line_cr "*** REBOOTING to normal security mode"
      /ciena/bin/evt_log ALERT "FAILED to enable enhanced security enforcement"
      saparam write $ParamType_LastResetReason $ResetReason_ErrorHandler
      saparam erase $ParamType_SecurityMode
      /sbin/reboot
    fi
    chgrp -R grpriv /flash1/fault
    chgrp -R grpriv /tmp/corefiles

    # FIPS POST
    fg_run "Running FIPS self-test" /ciena/bin/fips_post
    if [ "$?" -ne "0" ] ; then
       /ciena/bin/evt_log ALERT "FIPS POST failed"
       saparam write $ParamType_LastResetReason $ResetReason_ErrorHandler
       /sbin/reboot
    fi
else
    chgrp -R root /flash1/fault
    chgrp -R root /tmp/corefiles
fi
/ciena/bin/ubootcr -S 2> /dev/null

print_app_line_cr "Complete"

print_time_stamp "end rcS"
# End of rcS
