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

family=$(cat /family)

# 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

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

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

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

# Create well-known pipes
mknod -m 0666 /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 &
fi

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

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

# 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

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

# only do the RTC 2038 check on boards with an RTC
if board_has_rtc; then
    # The following function checks to see if the linux system date is the same
    # as the date retrieved by the hardware clock.  If it isn't, then that means
    # the linux date has rolled over on the signed integer.  In this case, we
    # should set the time to a good default e.g. January 1, 2000
    check_clock_okay ()
    {
        local cmd_hwclock=$(hwclock)
        local cmd_date=$(date)
        local hwdate
        local curdate

        #echo "hwclock $cmd_hwclock"
        #echo "date    $cmd_date"

        # Examples of the strings that have to be parsed:
        # root@(none):~# hwclock
        # Tue Jan 20 19:14:15 2009  0.000000 seconds
        # root@(none):~# date
        # Tue Jan 20 19:15:03 UTC 2009

        local hwclock_regex='^\S+\s+(\S+\s+\S+)\s+\S+\s+(\S+)'
        local date_regex='^\S+\s+(\S+\s+\S+)\s+\S+\s+\S+\s+(\S+)'

        if [[ $cmd_hwclock =~ $hwclock_regex ]]

        then
            hwdate="${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
            #echo "hwdate = $hwdate"

            if [[ $cmd_date =~ $date_regex ]]
            then
                curdate="${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
                #echo "curdate = $curdate"

                if [ "$hwdate" = "$curdate" ]
                then
                    return 0  # okay
                else
                    return 1  # different
                fi
            fi
        fi
        return 2  # error
    }

    if ! check_clock_okay
    then
        check_clock_okay
        case $? in
            0) echo okay ;;
            1) echo print_app_line_cr "Setting date: $(/bin/date -s 200001010000)"
                    hwclock -w ;;
            *) echo "Error: couldn't parse time" ;;
        esac
    fi
fi

REMOTE_IFNAME=remote
LOCAL_IFNAME=local
L3_IFNAME=saosL3

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)
        # 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/enableRoot
        print_result "$?"

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

    flash)
        fg_run "mount sysfs via fstab" /bin/mount /mnt/sysfs
        mount_log_partition
        if xftp_partition_supported; then
            fg_run "mount xftp partition" mount_xftp_partition
        fi
        if copy_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
        fg_run "check file manifest" /usr/bin/md5sum -cs /MANIFEST
        MANIFEST=$?
        check_reset_to_factory_defaults
        fg_run_no_output "setting local interface MAC" \
            ip link set dev $(get_local_if) address $(get_base_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 0770 /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

# 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

if [ -x /ciena/scripts/boardsupport_update.sh ] ; then 
    echo "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

# 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

if [ -f $KRN_CONF ]; then
    . $KRN_CONF
fi

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

# see if we need to flip banks due to corrupted files
if [ "$rootfs_location" = "flash" -a -n "$MANIFEST" -a "$MANIFEST" != 0 ]; then
    /ciena/bin/evt_log ALERT "file manifest integrity check failed"
    if [ "$KRN_AUTO" != "disable" -a "$KRN_MODE" != "debug" ]; then
        reboot          # To (presumably) alternate flash bank.
    fi
fi

# Did the bootloader swap banks on us?
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 [ "$rootfs_location" == "initramfs" ] ; then
    # These need to be run after /etc/group exists (for initramfs)
    /bin/chown -h root:root /*
    /bin/chown -Rh root:root /etc /tmp /bin /sbin /usr /var /root /mnt
    /bin/chmod 4111 /bin/su
    /bin/chmod 4111 /bin/root
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

# Export environment variables
source /etc/profile

# The guardian can only be started after the watchdog device is available
/etc/init.d/rc.guardian init

# Load FPGA
if [ -x /ciena/scripts/load_FPGA.sh ] ; then
    /ciena/scripts/load_FPGA.sh
fi

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 "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)
find /mnt/sysfs /tmp /etc \
   -xdev \
   -user root -group root \
   \( \( -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 \) \) \
     | xargs -r chmod g=u 2>/dev/null

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

# 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

print_app_line_cr "Complete"

# End of rcS
