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

###############################################################################
# FUNCTION:   flipBank
#
# Select the alternate application bank.  LEOS _cannot_ be running!
#
# ParamType_BootCookie is 282.  The poorly-documented -e option to
# hexdump takes a format string, which here calls for one 4-byte
# element printed as an unsigned integer.
#
###############################################################################
flipBank()
{
    BANK=`/mnt/apps/bin/saparam tofile 282 /proc/self/fd/1 | hexdump -n 4 -e '1/4 "%u"'`
    if [ $BANK = 0 ]; then      # bank = !bank;
        BANK=1
    else
        BANK=0
    fi
    /mnt/apps/bin/saparam write 282 $BANK
}

# 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/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 [ -n "$(kernel_arg console)" ] ; 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 &

    /bin/touch /tmp/console_enable
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

# 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.
echo "|/ciena/scripts/core_handler %e %p %t" > /proc/sys/kernel/core_pattern
fg_run "enabling core file generation" ulimit -c unlimited

print_app_line "enable panic on oom"
echo 1 > /proc/sys/vm/panic_on_oom
print_result $?

# make kernel min_free_kbytes match artamir; on brego it's
# set higher because of the extra RAM
print_app_line "setting kernel lowmem threshold"
echo 1019 > /proc/sys/vm/min_free_kbytes
print_result $?

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

board3960="/sys/bus/platform/devices/board_id.2"

# Set date to Jan 1 2000 if the date is 1970-01-01
# When running MIPS kernels 2.6.24 and higher, the date will default to the
# Unix epoch (Jan 1, 1970).  This is represented as a date of 0.  When PAM
# sees password entries that have been set on date 0, it assumes that the
# entries have been administratively expired (and this prevents LEOS logins).
# To avoid this, force the date to something non-zero.
if [ "$(date -I)" == "1970-01-01" ] ; then
    print_app_line_cr "Setting date: $(/bin/date -s 200001010000)"
    # linux driver will return 01-01-1970 00:00:00 if the date in the
    # RTC is bad, therefore if the date is 1970-01-01,
    # then the RTC should be set to a valid date too
    if [ -e "$board3960" ]; then
        hwclock -w
    fi
fi

# only do the RTC 2038 check on the 3960
if [ -e "$board3960" ]; 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
KRN_CONF=/mnt/sysfs/system/krn.conf

# Set panic timer
echo 10 > /proc/sys/kernel/panic

# 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)

case "$(kernel_arg root)" in
    /dev/mtdblock9)  rootfs_bank="A" ;;
    /dev/mtdblock12) 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
        #ln -s /dev/mtd4 /dev/params

        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 10
        # If we're a flash-based running system use the flash cookie jar,
        # else we're in some kind of development mode, so use the file-based
        # substitute you get with no /dev/params device.
        ln /dev/mtd4 /dev/params
        fg_run "mount kernel bank A" /bin/mount /mnt/kernelA
        fg_run "mount kernel bank B" /bin/mount /mnt/kernelB
        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 -csj2 /MANIFEST
        MANIFEST=$?
        check_reset_to_factory_defaults
        ;;

    *)
        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 exception log"   /ciena/bin/evt_setup except

# This must be done after the evt exception log is initialized
fg_run "capturing previous reboot reasons" /ciena/bin/evt_record_reset
if [ "$rootfs_location" == "flash" ] ; then
    # only makes sense to look at cookies on flash boot
    capture_reboot_cookie
fi

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

# Any user-installed pre-rc hook?
# These hooks are required because this rcS is on a read-only filesystem.
# We 'dot' 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

# grab KRN_MODE setting so we can determine ramsize
# (This must be done after mounting sysfs, but before using KRN variables)
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
    BANKSWP=`/mnt/apps/bin/saparam tofile 306 /proc/self/fd/1 | hexdump -n 4 -e '1/4 "%u"'`
    let BANKSWPD="$BANKSWP & 0x20000"
    if [ $BANKSWPD -ne 0 ] ; then
        /ciena/bin/evt_log ALERT "Flash bank swap occurred"
        let BANKSWP="$BANKSWP & ~0x20000"
        /mnt/apps/bin/saparam write 306 $BANKSWP
    fi
fi

echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

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

# Bullseye
if [ -f /mnt/apps/tmp/be_test.cov ] ; then
   cp /mnt/apps/tmp/be_test.cov /tmp
   chmod 0666 /tmp/be_test.cov
fi


# Initial configuration of telnet server.  Enabled when in debug mode.
if [ "$KRN_MODE" = "debug" ]; then
    /ciena/scripts/enable_telnet_debug
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

# Export environment variables
source /etc/profile

insmod_wrapper dying_gasp

if [ "$KRN_MODE" = "debug" ] ; then
    touch /dev/watchdog
    print_app_line_cr "no watchdog for KRN_MODE debug"
else
    insmod_wrapper softdog soft_margin=240

    # dead-dog must start after the watchdog is loaded
    bg_run_and_wait "starting dead-dog" /ciena/bin/dead-dog
    guard_file_add reboot dead-dog pid_only $(cat /var/run/dead-dog.pid)
fi

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

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

fg_run "Creating Remote Management interface" /ciena/bin/tapstart $REMOTE_IFNAME

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

# If the firmware's TFTPBOOT_CMD is out of date, fix it.  (For next time.)
if [ -x /sbin/fixbootcmd.sh ] ; then
    /sbin/fixbootcmd.sh
fi

# 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 | xargs -r chown root
find /mnt/sysfs -type d -a ! -group root  | xargs -r chgrp 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

# Set the keepalive timer so that dead connections drop after 10 minutes
echo 420 > /proc/sys/net/ipv4/tcp_keepalive_time
echo  30 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo   6 > /proc/sys/net/ipv4/tcp_keepalive_probes

# to resolve arp issue with remote and local interfaces
/sbin/sysctl -w net.ipv4.conf.all.arp_announce=2

# 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
