#
# Run-time Yocto platform environment. This file should be sourced.
#

# Make sure path is correctly set.
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin

# Set some important global variables.
SWI_OK=0
SWI_ERR=1
SWI_TRUE=1
SWI_FALSE=0

# Identify device type. This could be anything that would help determine who
# we are at runtime. But it would need to be unique for obvious reasons.
SYSTEM_ID=""

# Shell scripts do not return negative number, here define a number as
# the error return for some special purpose.
# Please make sure the return value of your function will not covered
# by this number before you are going to use this define.
SWI_ERR_MAX=255

# Used in security authentication.
# Note: SWI_OK=0 and SWI_ERR=1 are also used.
SWI_SEC_NONE=2
SWI_AUTH_PASS=3
SWI_AUTH_FAIL=4

# Mount point for flash partition used by Legato and UFS.
FLASH_MOUNTPOINT=/mnt/flash

# Mount point for legato flash partition
FLASH_MOUNTPOINT_LEGATO=/mnt/legato

# Rootfs backup root dir (for selected files under various conditions)
FLASH_MOUNTPOINT_RFS=${FLASH_MOUNTPOINT}/rootfs

# UFS root
UFS_ROOT=${FLASH_MOUNTPOINT}/ufs

# If Legato is wrapped in squashfs partition, it would be located
# on UBI partition 0.
UBI_USER0_LEGATO_VOLNUM=0
UBI_USER1_VOLNUM=0

# Size of /dev directory
DEVDIR_SIZE=262144

# overlayfs signature (for linux 3.14 kernel only)
OVERLAYFS_SIGNATURE=".overlayfs_fs"

# Name of this executable.
this_e=$( /usr/bin/basename $0 )

# If this file exists, udhcpc will not touch default route.
UDHCPC_KEEP_DEFAULT_ROUTE=/tmp/udhcpc_keep_default_route

# If this file exists, udhcpc will not touch resolv.conf .
UDHCPC_KEEP_DEFAULT_RESOLV=/tmp/udhcpc_keep_default_resolv

#
# Common helper functions
#

# Logger. Call it as:
#    swi_log "This is the system log."
swi_log()
{
    echo "${this_e}: $1" | tee /dev/console | logger
}

# constants to use with log_kernel for lev argument.
kern_emerg=0
kern_alert=1
kern_crit=2
kern_err=3
kern_warning=4
kern_notice=5
kern_info=6
kern_debug=7

# Log via kernel log from user space.
# Syntax: <level> <printf-format-string> <args>....
#         $1      $2                     $3 . ...
kern_log()
{
    local lev=$1
    local fmt=$2
    local pct=$(printf "%s" "$fmt" | sed -e s/%%//g -e s/[^%]//g)

    if [ $# -lt 2 ] ; then
        printf "kern_log: need at least two arguments%s\n" "$fmt"
        return 1
    fi

    case $lev in
      [0-7] )
        ;;
      * )
        printf "kern_log: %s is not a valid kernel log level\n" "$lev"
        return 1
        ;;
    esac

    shift; shift

    if [ ${#pct} -ne $# ] ; then
        printf "kern_log: mismatched format string and arguments\n" "$fmt"
        return 1
    fi

    printf "<%s>$fmt" $lev "$@" > /dev/kmsg
}

# function to get UART service
uart_get_srv()
{
    # UART Service type
    unset UART1_SERVICE UART2_SERVICE
    unset UART1_DEVICE UART2_DEVICE

    local UART_CONFIG_FILE=config

    UART1_DEVICE=`ls /sys/class/tty | grep tty'MSM0\|HSL0\|HS0'`
    local UART1_CONFIG=/sys/class/tty/${UART1_DEVICE}/device/config

    UART2_DEVICE=`ls /sys/class/tty | grep tty'MSM1\|HSL1|HS1'`
    local UART2_CONFIG=/sys/class/tty/${UART2_DEVICE}/device/config

    if [ -n "${UART1_DEVICE}" ] && [ -f "${UART1_CONFIG}" ] ; then
        UART1_SERVICE=$( cat ${UART1_CONFIG} )
        UART1_DEVICE=/dev/${UART1_DEVICE}
    fi

    if [ -n "${UART2_DEVICE}" ] && [ -f "${UART2_CONFIG}" ] ; then
        UART2_SERVICE=$( cat ${UART2_CONFIG} )
        UART2_DEVICE=/dev/${UART2_DEVICE}
    fi

    return 0
}

# Returns SWI_TRUE if unionfs should fudge rootfs.
is_fudge_ro_rootfs_allowed()
{
    local ret=${SWI_FALSE}
    local A=$( cat /proc/cmdline | grep -oe "fudge_ro_rootfs=\S*" )
    if [ "x${A}" == "xfudge_ro_rootfs=true" ] ; then
        ret=${SWI_TRUE}
    elif [ "x${A}" == "xfudge_ro_rootfs=false" ] ; then
        ret=${SWI_FALSE}
    else
        # Allow mount if rootfs is RO and flash mountpoint is RW
        local rootfs_ro=`mount | grep " on / " | grep -w ro`
        local flashfs_rw=`mount | grep " on $FLASH_MOUNTPOINT " | grep -w rw`
        if [ -z rootfs_ro ] || [ -z flashfs_rw ] ; then
            ret=${SWI_FALSE}
        else
            ret=${SWI_TRUE}
        fi
    fi

    if [ $ret -eq ${SWI_TRUE} ] ; then
        swi_log "RO rootfs fudge allowed."
    else
        swi_log "RO rootfs fudge NOT allowed."
    fi

    return ${ret}
}

# Returns SWI_TRUE if unionfs should mount the RW overlay on /etc
is_etc_overlay_disabled()
{
    local ret=${SWI_FALSE}
    local A=$( cat /proc/cmdline | grep -oe "ima_appraise=\S*" )
    if [ "x${A}" == "xima_appraise=enforce" ] ; then
        ret=${SWI_TRUE}
    fi

    if [ $ret -eq ${SWI_TRUE} ] ; then
        swi_log "Overlay over /etc is NOT allowed."
    else
        swi_log "Overlay over /etc is allowed"
    fi

    return ${ret}
}

# Wait until file shows up. Note that this will wait on any file and there
# will be no distinction between regular or device file. While covering wide
# range of cases, we may need to restrict this to device files in the future.
# Limit the time spent here to about 3 sec. If file does not show up for 3 sec.
# it will probably never show up.
# Note that the original max waiting time is 1 sec, now change to 3 sec because
# we found that in system reboot stress test, the ubi device cannot be generated
# within 1 sec occasionally after doing ubiattach.
wait_on_file()
{
    local cntmax=150
    local ret=${SWI_OK}

    while [ ! -e "$1" ] ; do
        usleep 20000
        cntmax=$( echo $(( ${cntmax} - 1 )) )
        if [ ${cntmax} -eq 0 ] ; then
            ret=${SWI_ERR}
            break
        fi
    done

    return ${ret}
}

# Check if this partition is erased by checking
# whether a few data is 0xff or not. If these data is 0xff,
# this partition is erased and return SWI_TRUE, otherwise,
# return SWI_FALSE.
#
# In principle we need to check all data in the mtd partition.
# But checking whole device is time consuming, so in this method,
# we only check the first three blocks data.
#
# Parameters:
#   $1 - mtd partition number
#
is_partition_erased()
{
    local mtd_dev_num=${1}
    local ret=${SWI_TRUE}
    local check_size=0
    local num_blocks=1

    if [ -x /usr/bin/swimtd ]; then
        # swimtd will check three blocks data. Return 0 if the
        # first three blocks have non 0xff data.
        /usr/bin/swimtd ${mtd_dev_num}
        if [ $? -eq 0 ]; then
            ret=${SWI_FALSE}
        fi
    else
        check_size=$(mtdinfo /dev/mtd${mtd_dev_num} | grep -i "Sub-page size" | awk '{print $3}' | xargs expr ${num_blocks} \*)

        # In order to be compatible with the platform that doesn't have swimtd,
        # check whether the data at the start of the partition is 0xff or not.
        # Note that nanddump can be slow.
        nanddump /dev/mtd${mtd_dev_num} -l $check_size --bb=skipbad -p 2>/dev/null \
            | grep -v -q "ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff" > /dev/null
        if [ $? -eq 0 ]; then
            ret=${SWI_FALSE}
        fi
    fi

    return ${ret}
}

#
# do_swap()
#
# This function is called whenever need to save bad image information and
# swap to another system. It first use swidssd to write bad image into shared
# memory, then echo 'b' to sysrq-trigger to reboot system immediately.
#
# $1 - the bad mtd partition name
#
do_swap()
{
    local name=
    local mask=
    local mtd_dev_name=${1}

    for item in ${DUAL_PARTI_LIST} ; do
        name=${item%_*}
        mask=${item#*_}

        if [ "${mtd_dev_name}" = "${name}" ]; then
            echo "The ${mtd_part_name} belong to dual system logic"
            /usr/bin/swidssd write $mask
            sync
            # echo 1 to sysrq to enable all functions of sysrq
            echo '1' > /proc/sys/kernel/sysrq
            # immediately reboot system without syncing or unmounting disk
            echo 'b' > /proc/sysrq-trigger
        fi
    done
    return ${SWI_ERR}
}

# If it is a dual system, the function return true, otherwise false
is_dual_system()
{
    if [ -e "/proc/proc_buffer" ] && [ -e /usr/bin/swidssd ]; then
        swi_log "it supports dual system"
        return ${SWI_TRUE}
    else
        return ${SWI_FALSE}
    fi
}

# This method is handling systems with dual system. In case, image
# needs to be swapped, this method will never return (system would
# reboot). If system is not dual boot, this method will return
# $SWI_ERR.
#
# $1 - the bad mtd partition number
#
swap_dual_system()
{
    local mtd_dev_num=${1}
    local mtd_dev_name=

    is_dual_system
    if [ $? -ne ${SWI_TRUE} ]; then
        echo "It is not dual system logic"
        return ${SWI_ERR}
    fi

    mtd_dev_name=$( cat /proc/mtd | grep mtd$mtd_dev_num | awk '{print $4}' | sed 's/"//g' )

    # this method may never return because it may swap to the backup system
    do_swap ${mtd_dev_name}
    if [ $? -eq ${SWI_ERR} ]; then
        echo "The partition should not be handled"
        return ${SWI_ERR}
    fi

    return ${SWI_OK}
}

# Determine if SMACK is enabled.
is_legato_smack_enabled()
{
    local ret=${SWI_OK}

    # Case if /legato is already mounted (after legato init), or first boot
    if [ -e "${FLASH_MOUNTPOINT_LEGATO}/SMACK_DISABLED" ]; then
        ret=${SWI_ERR}
    # Case if /legato is not mounted yet and we need to determine if we should run
    # with SMACK or not
    elif [ ! -e "/legato/systems" ]; then
        if [ -e "${FLASH_MOUNTPOINT}/legato/SMACK_DISABLED" ]; then
            # RW case
            ret=${SWI_ERR}
        elif [ ! -e "${FLASH_MOUNTPOINT}/legato/systems" ] &&
             [ -e "${FLASH_MOUNTPOINT_LEGATO}/SMACK_DISABLED" ]; then
            # RO case
            ret=${SWI_ERR}
        fi
    fi

    return ${ret}
}

#
# Determine if /etc overlay is mounted and writable. If it is, it will return
# SWI_OK .
#
is_etc_writable()
{
    local ret=${SWI_ERR}

    if mount | grep " on /etc type " | grep -wq rw; then
        ret=${SWI_OK}
    fi

    return ${ret}
}

#
# Determine if /mnt/flash is mounted and writable.
#
is_flash_mountpoint_writable()
{
    local ret=${SWI_ERR}

    if mount | grep " on ${FLASH_MOUNTPOINT} type " | grep -wq rw; then
        ret=${SWI_OK}
    fi

    return ${ret}
}

# Determine if we need to do bind mounting mounting of Nagger related files.
# Bindmounting of these files is required, if /etc is nor writeable.
# It will return SWI_OK, if bind mounting is required.
is_bindmount_nagger_files()
{
    local ret=${SWI_OK}

    # Do nothing if /etc is writable.
    if is_etc_writable; then
        return ${SWI_ERR}
    fi

    # If /mnt/flash is not writable there is no point to try to do bind
    # mounting.
    if ! is_flash_mountpoint_writable; then
        return ${SWI_ERR}
    fi

    return $ret;
}

#
# Append custom environment variables and functions here
#
#
# Run-time Yocto platform environment. This file should be sourced.
#

# Dual sub system flag
DS_SUB_SYSTEM_FLAG=0

# Flag to mount system 1
DS_SYSTEM_1_FLAG=100

# Flag to mount system 2
DS_SYSTEM_2_FLAG=200

# System 1 bad image mask
DS_SUB_SYSTEM_1_BAD_IAMGE_MASK=0

# System 2 bad image mask
DS_SUB_SYSTEM_2_BAD_IMAGE_MASK=0

# Mask of bad modem 1
MOD_MASK1=200

# Mask of bad modem 2
MOD_MASK2=400

# 20000 - Marks the image in lefwkro partition bad
LEG_MASK1=20000

# 40000 - Marks the image in lefwkro2 partition bad
LEG_MASK2=40000

# Mask of bad rootfs 1
SYS_MASK1=8000

# Mask of bad rootfs 2
SYS_MASK2=10000

# Partition name of dual system
MOD_NAME1=modem
SYS_NAME1=system
LEG_NAME1=lefwkro
MOD_NAME2=modem2
SYS_NAME2=system2
LEG_NAME2=lefwkro2

# List include 6 elements binding bad image mask
DUAL_PARTI_LIST="${MOD_NAME1}_${MOD_MASK1} \
      ${SYS_NAME1}_${SYS_MASK1} \
      ${LEG_NAME1}_${LEG_MASK1} \
      ${MOD_NAME2}_${MOD_MASK2} \
      ${SYS_NAME2}_${SYS_MASK2} \
      ${LEG_NAME2}_${LEG_MASK2} \
      "

# The name of the MTD partition where legato is installed
LEGATO_MTDEV_NAME=user0

# The name of the MTD partition where will be used to
# save customer data..
UFS_MTDEV_NAME=user1
USER_MTDEV_NAME=user1

# The name of the partition where userrw FS is mounted.
USERRW_MTDEV_NAME=user2

# Mount point for USERRW_MTDEV_NAME device.
USERRW_MTDEV_MOUNTPOINT=/mnt/userrw

# Root file system UBI device number. This is not mtd device
# number.
UBI_ROOTFS_DEVNUM=0

# If USER0 partition (or part of it) is mounted as UBI partition
# type (UBIFS, SQUASHFS-on-top-of-ubi, etc.), this is the
# device number which should be used.
UBI_USER0_DEVNUM=1

# If USER1 partition (or part of it) is mounted as UBI partition
# type (UBIFS, SQUASHFS-on-top-of-ubi, etc.), this is the
# device number which should be used.
UBI_USER1_DEVNUM=2
UBI_USER1_VOLNAME=user1_vol0

# UNIONFS type
UFS_T=overlayfs
