#!/bin/sh
#
# Add here mounts of the file systems needed early in the boot process.
# This file is reserved for system use, because system file systems typically
# need more flexibility when it comes down to mount paths and error handling.
# Customer file system mounts should go to fstab or elsewhere.
#
# import run environment
source /etc/run.env

# This executable
this_e=$( basename $0 )

# UBIFS mount options. Platforms may or may not have quota support. Hence, quota
# support must be separated from the rest of the default options.
UBI_MNTOPT_DEFAULT="sync,smackfsdef=_"
UBI_MNTOPT_QUOTA="usrquota,grpquota"

# YAFFS2 FS mount options. Do not change ecc for tags, you may break YAFFS2
# file systems on various platforms.
YAFFS2_MNTOPT="rw,tags-ecc-off,smackfsdef=_"

# Quotacheck binary may not be available due to licensing issues. Until
# this is resolved, we should keep quota support around. Also, it looks like
# that there is no way to programmatically do quota check, which may force
# users to use FreeBSD quotacheck.
# In addition, users could add back quota-tools package, but they would
# be liable for any licensing issues.
#
quota_check="/bin/true"
if [ -e /usr/sbin/quotacheck ] ; then
   quota_check="quotacheck"
fi

# Initialize YAFFS2 support related variables.
# Auto support detection can be overriden in run.env
yaffs2_kern_supported_init()
{
    if [ -z "$YAFFS2_KERN_SUPPORT" ] ; then
        if zcat /proc/config.gz | grep "YAFFS_YAFFS2=y" ; then
            YAFFS2_KERN_SUPPORT=true
        else
            YAFFS2_KERN_SUPPORT=false
        fi
    fi
}

# 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.
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}

}

# Get mtd device number which corresponds to mtd partition name.
# Parameters:
#    $1 - mtd partition name
#
# If there is an error, negative number will be returned.
get_mtdpart_dev_num()
{
    local mtd_part_name=${1}
    local mtd_dev_num=
    local err=$SWI_ERR_MAX

    if [ -z ${mtd_part_name} ] ; then
        swi_log "MTD partition name is empty."
        return ${err}
    fi

    mtd_dev_num=$( cat /proc/mtd | \
                   grep ${mtd_part_name} -w | \
                   awk '{print $1}' | \
                   sed 's/://g' | \
                   grep -o "[0-9]*" )

    if [ -z ${mtd_dev_num} ] ; then
        swi_log "MTD partition ${mtd_part_name} device number is not available."
        mtd_dev_num=${err}
    fi

    return ${mtd_dev_num}
}

# Get mtd partition size in MiB. Parameters:
#    $1 - mtd partition name
#
# If you are modifying any of it, please keep it simple. Bash math statements
# may be unreadable in its very basic form.
get_mtdpart_size_mib()
{
    local mtd_part_name=$1
    local mtd_part_size=0
    local err=0

    if [ -z ${mtd_part_name} ] ; then
        swi_log "MTD partition name is empty."
        return ${err}
    fi

    # Get mtd partition size in bytes (will be in hex format).
    mtd_part_size=$( cat /proc/mtd | grep ${mtd_part_name} -w | awk '{ print $2 }' )
    if [ -z ${mtd_part_size} ] ; then
        swi_log "MTD partition ${mtd_part_name} size is unavailable. "
        return ${err}
    fi

    # Get byte size of this partition in decimal format.
    mtd_part_size=$(( printf "%d" 0x${mtd_part_size} ))

    # We do have byte size of this partition, but we need its size in MiB.
    mtd_part_size=$( echo $(( ${mtd_part_size} / ( 1024 * 1024 ) )) )

    return ${mtd_part_size}
}

# Create single ubi volume. Parameters:
#   $1 - mtd partition name
#   $2 - ubi device number
#   $3 - ubi volume number associated with ubi device number
#   $4 - ubi volume name
#   $5 - ubi volume size. If not specified, whole MTD device will be used.
create_single_ubi_vol()
{
    local mtd_part_name=$1
    local ubi_dev_num=$2
    local ubi_vol_num=$3
    local ubi_vol_name=$4
    local ubi_vol_size=$5

    local mtd_dev_num=-1
    local ret=${SWI_OK}

    get_mtdpart_dev_num ${mtd_part_name}
    mtd_dev_num=$?
    if [ ${mtd_dev_num} -eq $SWI_ERR_MAX ] ; then
        # Error obtaining mtd device number, get out.
        return ${SWI_ERR}
    fi

    # Format MTD device for UBI use.
    ubiformat /dev/mtd${mtd_dev_num} -y
    if [ $? -ne 0 ] ; then
        swi_log "Cannot format mtd${mtd_dev_num}"
        return ${SWI_ERR}
    fi

    # Make link between physical and logical UBI device. If device does not
    # show up, tough luck.
    ubiattach -m ${mtd_dev_num} -d ${ubi_dev_num}
    if [ $? -ne 0 ] ; then
        swi_log "Unable to attach mtd partition ${mtd_part_name} to UBI logical device ${ubi_dev_num}"
        return ${SWI_ERR}
    fi
    wait_on_file "/dev/ubi${ubi_dev_num}"
    if [ $? -ne ${SWI_OK} ] ; then
        swi_log "Tired of waiting on /dev/ubi${ubi_dev_num}, exiting."
        return ${SWI_ERR}
    fi

    # If volume size is not specified, whole device will be used.
    if [ -z "${ubi_vol_size}" ] ; then
        ubi_vol_size=$( ubinfo -d ${ubi_dev_num} | \
                               grep "Amount of available logical eraseblocks" | \
                               awk '{ print $9 }' | \
                               xargs printf "%.0f" )
        if [ ${ubi_vol_size} -gt 0 ] ; then
            # Make sure that rounding is taken into account, otherwise mkvol
            # may fail.
            ubi_vol_size=$( echo $(( ${ubi_vol_size} - 1 )) )
        fi
    fi

    # Now, make UBI volume. If vol size happens to be 0 (small flash partition)
    # mkvol will fail, which is perfectly fine.
    swi_log "Making single volume, size ${ubi_vol_size}MiB on UBI device number ${ubi_dev_num}..."
    ubimkvol /dev/ubi${ubi_dev_num} -N ${ubi_vol_name} -s ${ubi_vol_size}MiB
    if [ $? -ne 0 ] ; then
        swi_log "Cannot make UBI volume ${ubi_vol_name} on UBI device number ${ubi_dev_num}"
        ret=${SWI_ERR}
    fi

    # Make sure detach happens. ubifs mount will attach it again.
    ubidetach -m ${mtd_dev_num}

    return ${ret}
}

# Check if YAFFS2 file system is empty. If it is empty, only "lost+found" dir
# will be located on file system. Parameters:
#   $1 - file system mount point
#
is_yaffs2_empty()
{
    local mntpt=$1
    local ret=${SWI_FALSE}
    local cdir=$( pwd )
    local var=

    # If file system is empty, it will have in its root the following entries:
    #   .
    #   ..
    #   lost+found
    cd ${mntpt}
    var=$( ls -al | wc -l )
    if [ ${var} -eq 3 ] ; then
        # It is empty.
        ret=${SWI_TRUE}
    fi

    cd ${cdir}
    return ${ret}
}

# Perform quotacheck and repair quota files
# in case of a problem.
# $1 - mount point
quotacheck_ug()
{

    mntpt=${1}
    ug_sw=ug
    ret=${SWI_OK}
    ug_str=
    qc_sw=


    ug_sw="ug"
    qc_sw="-${ug_sw}mb"

    # Check both user and group at the same time. If group file is corrupt
    # quotacheck will stop and wait for user input, but show must go on.
    # Therefore, we need 'yes' in order to get things moving again.
    yes | $quota_check ${qc_sw} ${mntpt}
    if [ $? -eq 0 ] ; then
        return ${SWI_OK}
    fi

    # Quotacheck failed, now we go into repair mode, and test
    # quotas individually.
    list="u g"
    for item in ${list} ; do

        ug_sw=${item}

        if [ "x${ug_sw}" = "xu" ] ; then
            ug_str="user"
        elif [ "x${ug_sw}" = "xg" ] ; then
            ug_str="group"
        else
            swi_log "Invalid parameter '${ug_sw}'."
            return ${SWI_ERR}
        fi

        qc_sw="-${ug_sw}mb"

        $quota_check ${qc_sw} ${mntpt}
        if [ $? -ne 0 ] ; then

            # Quotacheck failed.

            # if there is a backup file, try to use it.
            if [ -s ${mntpt}/aquota.${ug_str}~ ] ; then
                swi_log "Quota check failed, trying to use '${ug_str}' backup file."
                rm -f ${mntpt}/aquota.${ug_str}
                cp -af ${mntpt}/aquota.${ug_str}~ ${mntpt}/aquota.${ug_str}

                $quota_check ${qc_sw} ${mntpt}
                if [ $? -eq 0 ] ; then
                    swi_log "Quota check done, '${ug_str}' backup file looks healthy."
                    continue
                fi
                swi_log "Quota check using '${ug_str}' backup file failed, '${ug_str}' file must be created."
            fi

            # Make sure corrupt backup file is not used. Otherwise, we may end up
            # using corrupt backup file again, if new file fails next time around.
            swi_log "Removing corrupt '${ug_str}' files."
            rm -f ${mntpt}/aquota.${ug_str}*

            # Things did not go that well with backup file, try to recreate quota file.
            qc_sw="${qc_sw}""c"

            $quota_check ${qc_sw} ${mntpt}
            if [ $? -ne 0 ] ; then
                swi_log "Quota check failed while creating '${ug_str}' quota file, giving up."

                # Any leftovers may indicate to other parties that quotas are actually
                # functional, where in fact they are not.
                rm -f ${mntpt}/aquota.${ug_str}*
                ret=${SWI_ERR}
                break
            else
                # Make sure that backup file always exists
                cp -af ${mntpt}/aquota.${ug_str} ${mntpt}/aquota.${ug_str}~
            fi
        fi

    done

    return ${ret}
}

# Generic function to active DM verity feature. Parameters:
#   $1 - ubi logical device number
#   $2 - ubi logical volume number for raw image
#   $3 - ubi logical volume number for hash bin
#   $4 - ubi logical volume number for root hash
#   $5 - DM verity device name for the partition
mount_as_dm_verity() {
    local ubi_dev_num=$1
    local ubi_vol_num_image=$2
    local ubi_vol_num_hash=$3
    local ubi_vol_num_rhash=$4
    local dm_device_name=$5
    local root_hash=

    # UBI partitions for squashfs image, hash and root-hash
    local ubi_img_dev=/dev/ubi${ubi_dev_num}_${ubi_vol_num_image}
    local ubi_hash_dev=/dev/ubi${ubi_dev_num}_${ubi_vol_num_hash}
    local ubi_rhash_dev=/dev/ubi${ubi_dev_num}_${ubi_vol_num_rhash}

    local ubi_img_block_dev=/dev/ubiblock${ubi_dev_num}_${ubi_vol_num_image}
    local ubi_hash_block_dev=/dev/ubiblock${ubi_dev_num}_${ubi_vol_num_hash}

    if grep 'verity=on' /proc/cmdline > /dev/null; then
        DM_VERITY_ENCRYPT="on"
    fi

    if [ "x$DM_VERITY_ENCRYPT" != "xon" ]; then
        swi_log "DM verity is not enabled."
        return ${SWI_ERR}
    fi

    if ! [ -c "${ubi_rhash_dev}" ]; then
        swi_log "Cannot find root hash volume ${ubi_rhash_dev}."
        return ${SWI_ERR}
    fi

    DM_FLAG=$(dd if=${ubi_hash_dev} count=1 bs=4 2>/dev/null)
    if [ "x$DM_FLAG" != "xveri" ]; then
        swi_log "Cannot find hash volume ${ubi_hash_dev}."
        return ${SWI_ERR}
    fi

    # Create UBI block device for squashfs image
    if ! [ -b "${ubi_img_block_dev}" ]; then
        ubiblock --create ${ubi_img_dev}
        if [ $? -ne 0 ] ; then
            swi_log "Unable to create ${ubi_img_block_dev}."
            return ${SWI_ERR}
        fi
        wait_on_file "${ubi_img_block_dev}"
        if [ $? -ne ${SWI_OK} ] ; then
            swi_log "Tired of waiting on ${ubi_img_block_dev}, exiting."
            return ${SWI_ERR}
        fi
    fi

    # Dm-verity hash tree table is located on this volume, check it and prepare it for use.
    if ! [ -b "${ubi_hash_block_dev}" ]; then
        ubiblock --create ${ubi_hash_dev}
        if [ $? -ne 0 ] ; then
            swi_log "Unable to create ${ubi_hash_block_dev}."
            return ${SWI_ERR}
        fi
        wait_on_file "${ubi_hash_block_dev}"
        if [ $? -ne ${SWI_OK} ] ; then
            swi_log "Tired of waiting on ${ubi_hash_block_dev}, exiting."
            return ${SWI_ERR}
        fi
    fi

    # Get the root hash from rhash volume
    root_hash=$(dd if=${ubi_rhash_dev} count=1 bs=64 2>/dev/null)

    # Create Dm-verity layer
    veritysetup create ${dm_device_name} ${ubi_img_block_dev} ${ubi_hash_block_dev} ${root_hash}
    if [ $? -ne 0 ] ; then
        swi_log "Device: ${dm_device_name} ubiImgBlock:${ubi_img_block_dev} hashBlock:${ubi_hash_block_dev}"
        swi_log "root_hash:${root_hash}"
        swi_log "Dm-verity partition creation failed."
        return ${SWI_ERR}
    fi
    return ${SWI_OK}
}

# Generic function to mount ubi filesystems. Parameters:
#   $1 - mtd partition name
#   $2 - file system mount point
#   $3 - file system type to mount
#   $4 - ubi logical device number
#   $5 - ubi logical volume number
#   $6 - ubifs mount options (default ones should be excluded)
# Other parameters for DM verity and security
#   $7 - DM verity device name for the partition
#   $8 - Security check status
mount_ubifs()
{
    local mtd_part_name=$1
    local mntpt=$2
    local fstype=$3
    local ubi_dev_num=$4
    local ubi_vol_num=$5
    local ubifs_mnt_options=$6

    # Parameters for DM verity
    local dm_device_name=$7
    local ubi_hash_dev=/dev/ubi${ubi_dev_num}_${UBI_HASH_VOLNUM}

    # Parameters for security check status
    local secure=$8
    local dm_mount_point=
    local mtd_dev_num=
    local ubi_dev_vol_pair=${ubi_dev_num}_${ubi_vol_num}
    local ret=${SWI_OK}
    local ubidev_name=ubi

    # Get mtd device number
    get_mtdpart_dev_num ${mtd_part_name}
    mtd_dev_num=$?
    if [ ${mtd_dev_num} -eq $SWI_ERR_MAX ] ; then
        # Error obtaining mtd device number, get out.
        return ${SWI_ERR}
    fi

    is_partition_erased ${mtd_dev_num}
    if [ $? -eq ${SWI_TRUE} ] ; then
        swi_log "UBI: mtd ${mtd_dev_num} does not contain UBI container."
        return ${SWI_ERR}
    fi

    # Make link between physical and logical UBI device. If device does not
    # show up, we need to exit.
    # If device exist do not detach and then attach again - save boot up time
    if ! [ -c "/dev/ubi${ubi_dev_num}" ]; then
        ubiattach -m ${mtd_dev_num} -d ${ubi_dev_num}
        if [ $? -ne 0 ] ; then
            swi_log "Unable to attach mtd partition ${mtd_part_name} to UBI logical device ${ubi_dev_num}"
            return ${SWI_ERR}
        fi
        wait_on_file "/dev/ubi${ubi_dev_vol_pair}"
        if [ $? -ne ${SWI_OK} ] ; then
            swi_log "Tired of waiting on /dev/ubi${ubi_dev_vol_pair}, exiting."
            return ${SWI_ERR}
        fi
    fi

    # Create corresponding block device. It is not needed for UBIFS volumes,
    # but it is needed for volumes containg file systems like squashfs.
    # If device does not show up for whatever reason, we need to exit.
    if [ "${fstype}" == "squashfs" ] ; then
        SQFS_FLAG=$(dd if=/dev/ubi${ubi_dev_vol_pair} count=1 bs=4 2>/dev/null)
        if echo $SQFS_FLAG | grep 'hsqs' > /dev/null; then
            # squashfs volume, create UBI block device
            if ! [ -b "/dev/ubiblock${ubi_dev_vol_pair}" ]; then
                ubiblock --create /dev/ubi${ubi_dev_vol_pair}
                if [ $? -ne 0 ] ; then
                    swi_log "Unable to use ubi${ubi_dev_num} partition ${ubi_vol_num}"
                    ubidetach -m ${mtd_dev_num}
                    return ${SWI_ERR}
                fi
                wait_on_file "/dev/ubiblock${ubi_dev_vol_pair}"
                if [ $? -ne ${SWI_OK} ] ; then
                    swi_log "Tired of waiting on /dev/ubiblock${ubi_dev_vol_pair}, exiting."
                    return ${SWI_ERR}
                fi

            fi

            # Check the UBI volume which may contain the hash for DM verity.
            if [ -c "${ubi_hash_dev}" -a -n "${dm_device_name}" ]; then
                # Try to enable DM verity.
                mount_as_dm_verity ${ubi_dev_num}      \
                                   ${UBI_IMAGE_VOLNUM}      \
                                   ${UBI_HASH_VOLNUM}  \
                                   ${UBI_RHASH_VOLNUM} \
                                   ${dm_device_name}
                if [ $? -eq ${SWI_OK} ] ; then
                    # All DM-Verity mount points will use /dev/mapper as their root directory (e.g.
                    # /dev/mapper/<mount-point>).
                    dm_mount_point="/dev/mapper/${dm_device_name}"
                fi
            fi

        fi
        # Mount UBI volume. squashfs UBI volumes are using ubiblock instead of ubi
        # device.

        ubidev_name=ubiblock
    fi

    if [ -b "${dm_mount_point}" ]; then
        mount -t ${fstype} ${dm_mount_point} ${mntpt} \
              -oro,${UBI_MNTOPT_DEFAULT}
        if [ $? -ne 0 ] ; then
            swi_log "Unable to mount ${dm_mount_point} onto ${mntpt}."
            veritysetup remove ${dm_device_name}
            return ${SWI_ERR}
        fi
    else
        # Secure version should work with UBI + squashfs + dm-verity,
        # so return SWI_ERR when it is secure version and dm-verity cannot work.
        if [ "x${secure}" == "x${SWI_AUTH_PASS}" ]; then
            swi_log "Security authentication failure."
            return ${SWI_ERR}
        fi

        mount -t ${fstype} /dev/${ubidev_name}${ubi_dev_vol_pair} ${mntpt} \
          -o${UBI_MNTOPT_DEFAULT},${ubifs_mnt_options}
        if [ $? -ne 0 ] ; then
            # detach will release block device as well.
            swi_log "Unable to mount /dev/ubiblock${ubi_dev_vol_pair} onto ${mntpt}."
            ubidetach -m ${mtd_dev_num}
            return ${SWI_ERR}
        fi
    fi

    # If quota options are passed in, do quota check. Use neat shell substitute
    # trick. Parameters passed must be in the same order as bellow in order
    # for this to work. Only if there is exact match, echo output will be
    # an empty string.
    # squashfs mount will fail this test, because quota options are not
    # passed in.
    mnt_opts="${UBI_MNTOPT_DEFAULT},${ubifs_mnt_options}"
    var=$( echo -n "${mnt_opts/${UBI_MNTOPT_DEFAULT},${UBI_MNTOPT_QUOTA},rw/}" )
    if [ -z ${var} ] ; then
        # Quota options were passed in, do file system quota check.
        swi_log "Performing quota check on file system mounted at ${mntpt}"

        quotacheck_ug ${mntpt}
        if [ $? -ne 0 ] ; then
            ret=${SWI_ERR}
        fi
    fi

    # Release resources in case of error.
    if [ ${ret} -ne ${SWI_OK} ] ; then
        umount ${mntpt}
        ubidetach -m ${mtd_dev_num}
    fi

    return ${ret}
}

# Try to mount R/W UBIFS using various mount options. The reason for this is that
# some of the platforms are UBIFS capable, but do not have quota support.
# Always try to mount with quota support first. Parameters:
#   $1 - mtd partition name
#   $2 - file system mount point
#   $3 - UBI logical device number
#   $4 - UBI volume associated with UBI logical device number
mount_ubifs_multi_mount_options()
{
    local mtd_part_name=$1
    local mntpt=$2
    local ubi_dev_num=$3
    local ubi_vol_num=$4

    # Try to mount UBIFS partition using various mount options. Do not change
    # parameter order, you will break things.
    list="${UBI_MNTOPT_QUOTA},rw rw"
    for item in ${list} ; do
        swi_log "Trying to mount UBIFS on ${mntpt} using [${item}] mount options..."
        mount_ubifs ${mtd_part_name} ${mntpt} \
                    ubifs ${ubi_dev_num} ${ubi_vol_num} "${item}"
        if [ $? -eq ${SWI_OK} ]; then
            swi_log "UBIFS volume successfully mounted on ${mntpt}"
            return ${SWI_OK}
        fi
    done

    return ${SWI_ERR}
}


# Generic function to mount yaffs2 filesystem. Parameters:
# $1 - mtd partition name
mount_yaffs_fs()
{
    local ret=${SWI_OK}
    local mtd_part_name=$1
    local mtd_dev_num=
    local mntpt=$2

    if ! ${YAFFS2_KERN_SUPPORT}; then
        swi_log "Trying to mount as yaffs2 while there is no support, aborting."
        return ${SWI_ERR}
    fi

    # Get the device number
    get_mtdpart_dev_num ${mtd_part_name}
    mtd_dev_num=$?
    if [ ${mtd_dev_num} -eq $SWI_ERR_MAX ] ; then
        # Error obtaining mtd device number, get out.
        return ${SWI_ERR}
    fi

    # Mount YAFFS2 volume. It is highly unlikely that it would fail.
    mount -t yaffs2 /dev/mtdblock${mtd_dev_num} ${mntpt} -o${YAFFS2_MNTOPT}
    if [ $? -ne 0 ] ; then
        swi_log "Unable to mount /dev/mtdblock${mtd_dev_num} onto ${mntpt}."
        ret=${SWI_ERR}
    fi

    return ${ret}
}

# Mount user partition. UBIFS will be used if all possible unless YAFFS2 is
# forced by the user.
mount_early_user_start()
{
    local mtd_part_name=${USER_MTDEV_NAME}
    local mtd_part_size=0
    local var=""

    is_fudge_ro_rootfs_allowed
    if [ $? -ne ${SWI_TRUE} ] ; then
        swi_log "Not allowed to fudge rootfs."
        return ${SWI_OK}
    fi

    if [ -z "$mtd_part_name" ]; then
        return ${SWI_OK}
    fi

    # User may be forcing file system. We will let upper layers decide what is
    # going to happen, if there is an error.

    # Try UBIFS first.
    grep -w "user1_fs=ubifs" /proc/cmdline > /dev/null
    if [ $? -eq 0 ] ; then

        swi_log "User is forcing ${mtd_part_name} file system to be ubifs."

        # Try to mount existing UBIFS partition first.
        mount_ubifs_multi_mount_options ${mtd_part_name} \
                                        ${FLASH_MOUNTPOINT} \
                                        ${UBI_USER1_DEVNUM} \
                                        ${UBI_USER1_VOLNUM}
        if [ $? -eq ${SWI_OK} ] ; then
            # It actually worked, and we do not have to be here any more.
            return ${SWI_OK}
        fi

        # That did not work, so we need to force this partition to be single
        # volume UBIFS .
        create_single_ubi_vol ${mtd_part_name} ${UBI_USER1_DEVNUM} \
                              ${UBI_USER1_VOLNUM} ${UBI_USER1_VOLNAME}
        if [ $? -ne ${SWI_OK} ] ; then
             # UBI volume creation did not work, so get out since user wanted
             # UBIFS.
             return ${SWI_ERR}
        fi

        # Now we mount UBIFS volume created above.
        mount_ubifs_multi_mount_options ${mtd_part_name} \
                                        ${FLASH_MOUNTPOINT} \
                                        ${UBI_USER1_DEVNUM} \
                                        ${UBI_USER1_VOLNUM}
        if [ $? -ne ${SWI_OK} ] ; then
            # There is nothing we can do here, user wanted forced UBIFS file
            # system, but we cannot mount it.
            return ${SWI_ERR}
        fi

        # user partition is ubifs now.
        return ${SWI_OK}

    fi

    grep -w "user1_fs=yaffs2" /proc/cmdline > /dev/null
    if [ $? -eq 0 ] ; then
        # yaffs2 cannot fail unless the whole flash is dead.
        swi_log "User is forcing ${mtd_part_name} file system to be yaffs2."
        mount_yaffs_fs ${mtd_part_name} ${FLASH_MOUNTPOINT}
        return ${SWI_OK}
    fi

    # We are passed user forced options, try to mount UBIFS partition first.
    mount_ubifs_multi_mount_options ${mtd_part_name} \
                                    ${FLASH_MOUNTPOINT} \
                                    ${UBI_USER1_DEVNUM} \
                                    ${UBI_USER1_VOLNUM}
    if [ $? -eq ${SWI_OK} ] ; then
        # It actually worked, and we do not have to be here any more.
        return ${SWI_OK}
    fi

    if ${YAFFS2_KERN_SUPPORT}; then
        # Mount YAFFS2 partition. If empty, we may as well have it as UBIFS.
        mount_yaffs_fs ${mtd_part_name} ${FLASH_MOUNTPOINT}
        is_yaffs2_empty ${FLASH_MOUNTPOINT}
        if [ $? -ne ${SWI_TRUE} ] ; then
            # Filesystem is not empty
            return ${SWI_OK}
        fi
        swi_log "YAFFS2 file system on ${mtd_part_name} partition is empty."
    fi

    swi_log "Forcing ${mtd_part_name} to be UBIFS."
    umount ${FLASH_MOUNTPOINT}

    create_single_ubi_vol ${mtd_part_name} ${UBI_USER1_DEVNUM} \
                          ${UBI_USER1_VOLNUM} ${UBI_USER1_VOLNAME}
    if [ $? -ne ${SWI_OK} ] ; then
         # UBI volume creation did not work, go back to YAFFS2.
         mount_yaffs_fs ${mtd_part_name} ${FLASH_MOUNTPOINT}
         return ${SWI_OK}
    fi
    # It worked, try to mount it.
    mount_ubifs_multi_mount_options ${mtd_part_name} \
                                    ${FLASH_MOUNTPOINT} \
                                    ${UBI_USER1_DEVNUM} \
                                    ${UBI_USER1_VOLNUM}
    if [ $? -ne ${SWI_OK} ] ; then
        # UBI volume mount did not work, go back to YAFFS2.
        mount_yaffs_fs ${mtd_part_name} ${FLASH_MOUNTPOINT}
        return ${SWI_OK}
    fi

    return ${SWI_OK}
}

# Unmount user partition
mount_early_user_stop()
{
    local mntpt=${FLASH_MOUNTPOINT}
    local is_ubifs=
    local mtd_dev_num=
    local ret=${SWI_OK}

    is_fudge_ro_rootfs_allowed
    if [ $? -ne ${SWI_TRUE} ] ; then
        swi_log "Nothing to do (fudging of rootfs is not allowed)."
        return ${ret}
    fi

    is_ubifs=$( grep -w "${FLASH_MOUNTPOINT} ubifs" /proc/mounts )

    # There is nothing we can do if umount fails, so do not check
    # the result of the operation. The same goes for ubidetach.
    # Note that unmount will be successful, because it is "lazy". This will
    # keep new clients away from this mount, but the old ones will still be
    # there. The final cleanup would occur later in rcK.
    umount -l ${mntpt}
    if [ -n "${is_ubifs}" ] ; then
        get_mtdpart_dev_num ${USER_MTDEV_NAME}
        mtd_dev_num=$?
        if [ ! ${mtd_dev_num} -eq $SWI_ERR_MAX ] ; then
            # detach takes care of the block device as well.
            ubidetach -m ${mtd_dev_num} >/dev/null 2>&1
            if [ $? -ne 0 ] ; then
                swi_log "ubidetach failed for device /dev/mtd${mtd_dev_num}, rcK should take care of it."
            fi
        fi
    fi

    return ${SWI_OK}
}

# This function is used to check secure mode or do security authentication
# according to the input parameters.
#
# Check secure mode:
# The utility swi_auth read the fuse from specify register, and return
# secure or non-secure.
#
# Security authentication:
# The utility will verify the signature of the image in the ubi partitions
# ubix_2 ~ ubix_4.
#
# If in secure mode, the following images format is expected.
# ubix_0 -- file system squashfs image (squashfs on top of UBI).
# ubix_1 -- hash tree of squashfs image (binary,generated by veritysetup)
# ubix_2 -- root hash (ascii hex,generated by veritysetup)
# ubix_3 -- root hash after signature (binary)
# ubix_4 -- cert chain (some of the keys, used for signature)
#
# Here is the usage for the utility swi_auth
# swi_auth [fuse|nfuse] [ubi_dev_num] [platform]
#    fuse - only check secure mode, return secure or non-secure
#    nfuse - skip checking secure mode, only do security authentication
#    ubi_dev_num - ubix (do security authentication need this parameter)
#    platform - 9x40,9x28,9x15. default is 9x40
# return:
#    1 ~ 3 - error code
#    4 - non-secure mode
#    5 - secure mode
#    6 - authentication successful
#
# Check security authentication. Parameters:
#   $1 - ubi logical device number
#   $2 - mtd partition number
#   $3 - support not UBI image in this mtd partition:
#      - ${SWI_TRUE}: Only check security when it is UBI image
#      - ${SWI_FALSE}:Not UBI image is not allowed for security CUP
check_security_auth()
{
    local ubi_dev_num=$1
    local mtd_dev_num=$2
    local support_not_ubi=$3
    local ret_auth=${SWI_AUTH_FAIL}
    local ubi_vol_total_num=0
    local auth_cmd="/usr/bin/swi_auth"

    # UBI volume devices for root-hash, signature-root-hash and cert-chain
    local ubi_rhash_dev=/dev/ubi${ubi_dev_num}_${UBI_RHASH_VOLNUM}
    local ubi_srh_dev=/dev/ubi${ubi_dev_num}_${UBI_SRH_VOLNUM}
    local ubi_cert_dev=/dev/ubi${ubi_dev_num}_${UBI_CERT_VOLNUM}
    local ubi_dev_list=

    if ! [ -x ${auth_cmd} ] ; then
        swi_log "File ${auth_cmd} does not exist or is not executable."
        return ${SWI_ERR}
    fi

    # Read fuse from register to get secure mode.
    ${auth_cmd} fuse
    ret_auth=$?
    if [ ${ret_auth} -eq 4 ] ; then
        # Any other errors should continue to avoid secure hole.
        swi_log "Non-secure."
        return ${SWI_SEC_NONE}
    fi

    # We need to allow module to boot up in the case partition(e.g. legato)
    # doesn't have any data even if the module has been fused.
    # As a result, ${support_not_ubi} is used to specify this partition
    # in this case. The caller of this function only take ${SWI_AUTH_FAIL}
    # as authentication failure which need futher action.
    is_partition_erased ${mtd_dev_num}
    if [ $? -eq ${SWI_TRUE} ] ; then
        if [ ${support_not_ubi} -eq ${SWI_TRUE} ] ; then
            return ${SWI_ERR}
        else
            swi_log "Cannot find UBI container on MTD ${mtd_dev_num}."
            return ${SWI_AUTH_FAIL}
        fi
    fi

    # Make link between physical and logical UBI device.
    ubiattach -m ${mtd_dev_num} -d ${ubi_dev_num}
    if [ $? -ne 0 ] ; then
        swi_log "Unable to attach mtd ${mtd_dev_num} to UBI logical device ${ubi_dev_num}."
        return ${SWI_AUTH_FAIL}
    fi

    # Important:
    # After ubiattach, for multi volumes UBI image, we need to wait for all the UBI
    # volumes ready which are needed at the following step. There is a low probability
    # that when the last volume is ready but some of the other volumes are not ready.
    # E.g ubix_4 is ready, but ubix_2 or ubix_3 is not ready.
    # Wait for all the UBI volumes that used for security authentication.
    ubi_dev_list="
                  ${ubi_rhash_dev}
                  ${ubi_srh_dev}
                  ${ubi_cert_dev}
                  "
    for ubi_dev in ${ubi_dev_list} ; do
        wait_on_file "${ubi_dev}"
        if [ $? -ne ${SWI_OK} ] ; then
            swi_log "Tired of waiting on ${ubi_dev}."
            return ${SWI_AUTH_FAIL}
        fi
    done

    # Do authentication and handle the result.
    ${auth_cmd} nfuse ubi${ubi_dev_num}
    ret_auth=$?
    case "${ret_auth}" in
        6)
            # This is secure version should work with UBI.
            swi_log "Secure version."
            ubi_vol_total_num=$(cat /sys/class/ubi/ubi${ubi_dev_num}/volumes_count)
            if [ ${ubi_vol_total_num} != "${DM_SEC_UBI_VOL_COUNT}" ] ; then
                swi_log "DM verity with secure version should has $DM_SEC_UBI_VOL_COUNT UBI volumes."
                return ${SWI_AUTH_FAIL}
            fi
            return ${SWI_AUTH_PASS}
        ;;
        *)
            swi_log "Authentication failure, error: ${ret_auth}"
            return  ${SWI_AUTH_FAIL}
        ;;
    esac
}

# This method should be called in case where there is a Legato image mount
# failure for whatever reason. The reason may be:
# a. Authentication of Legato image failed
# b. Mounting of Legato image failed
#
# If Legato image is bad, and this is dual boot system, this method would never
# return (system will reboot). The same is true for authentication failure.
# If this is not dual boot system, or there is no authentication failure, this
# method will return SWI_FALSE.
#
# Parameters:
#   $1 - mtd partition number
#   $2 - Security check status
handle_legato_fail_issue()
{
    local mtd_dev_num=$1
    local secure=$2
    local req_reboot=$SWI_FALSE

    # ${secure} is the return value of check_security_auth(), which is the authentication
    # return value. ${SWI_AUTH_FAIL} means authentication failure, we need to reboot system
    # surely. In the other case is that, secure authentication is passed with ${SWI_AUTH_PASS}
    # but mount falied (so go into this function), we also need to reboot system.
    if [ ${secure} -eq ${SWI_AUTH_FAIL} ] || [ ${secure} -eq ${SWI_AUTH_PASS} ]; then
        req_reboot=$SWI_TRUE
    fi

    # If mount failed and the legato partition is not empty, need to reboot module.
    is_partition_erased $mtd_dev_num
    if [ $? -ne $SWI_TRUE ]; then
        req_reboot=$SWI_TRUE
    fi

    # /proc/proc_buffer exists in dual boot systems only. It contains
    # partition names which have backup images (e.g. lefwkro and lefwkro2).
    # In case of dual boot systems, we need to check if we need to swap to
    # backup image if "running" image could not be mounted for whatever
    # reason.
    if [ $req_reboot = $SWI_TRUE ]; then
        # There is a Legato backup image. We do not need to investigate
        # failure reason, because partition failed to mount. We need
        # to swap this Legato image with good one.
        swap_dual_system $mtd_dev_num
        if [ $? -ne ${SWI_TRUE} ]; then
            echo "The partition should not be handled"
            return ${SWI_FALSE}
        fi
    fi

    return ${SWI_FALSE}
}

# Mount user0 Legato "backup" partition. This partition may be squashfs or
# yaffs2. Since yaffs2 does not recognize any other file systems, try to
# mount all other file systems first. If all fails, mount yaffs2 partition.
mount_early_legato_start()
{
    local ret=${SWI_OK}
    local secure=${SWI_AUTH_FAIL}
    local mtd_dev_num=0

    DS_LINUX_SUB_SYSTEM_FLAG=000
    is_dual_system
    if [ $? -eq ${SWI_TRUE} ]; then
        /usr/bin/swidssd read linux
        DS_LINUX_SUB_SYSTEM_FLAG=$?
    fi

    if [ $DS_LINUX_SUB_SYSTEM_FLAG -eq $DS_SYSTEM_2_FLAG ]; then
        LEGATO_MTDEV_NAME=${LEGATO_MTDEV_NAME}2
    fi
    echo "mount Legato from partition $LEGATO_MTDEV_NAME"

    if [ ! -d ${FLASH_MOUNTPOINT_LEGATO} ]; then
        mkdir -p ${FLASH_MOUNTPOINT_LEGATO}
        if [ $? -ne 0 ]; then
            swi_log "Unable to create mount point ${FLASH_MOUNTPOINT_LEGATO}"
            return ${SWI_ERR}
        fi
    fi

    # Get mtd device number
    get_mtdpart_dev_num ${LEGATO_MTDEV_NAME}
    mtd_dev_num=$?
    if [ ${mtd_dev_num} -eq $SWI_ERR_MAX ] ; then
        # Error obtaining mtd device number, get out.
        return ${SWI_ERR}
    fi

    check_security_auth ${UBI_USER0_DEVNUM}  \
                        ${mtd_dev_num}       \
                        ${SWI_TRUE}
    secure=$?
    if [ ${secure} -eq ${SWI_AUTH_FAIL} ]; then
        # Security authentication failure, get out.
        swi_log "Security authentication failure."
        handle_legato_fail_issue ${mtd_dev_num} ${secure}
    fi

    # Try to mount squashfs file system first. It is sitting on top of
    # UBI volume, and we need to use ubifs related commands to try to
    # mount it.
    mount_ubifs ${LEGATO_MTDEV_NAME} ${FLASH_MOUNTPOINT_LEGATO} \
                squashfs ${UBI_USER0_DEVNUM} ${UBI_USER0_LEGATO_VOLNUM} ro \
                ${DM_LGT_NOD_NAME} \
                ${secure}
    ret=$?
    if [ ${ret} -eq ${SWI_OK} ]; then
        swi_log "SQUASHFS successfully mounted on ${FLASH_MOUNTPOINT_LEGATO}"
        return ${ret}
    else
        handle_legato_fail_issue ${mtd_dev_num} ${secure}
    fi

    if ${YAFFS2_KERN_SUPPORT}; then
        # Mounting of squashfs failed. YAFFS2 "takes no prisoners" and it will mount
        # even if that means wiping out existing file system(s).
        mount_yaffs_fs ${LEGATO_MTDEV_NAME} ${FLASH_MOUNTPOINT_LEGATO}
        return $?
    else
        swi_log "Unable to find a way to mount ${LEGATO_MTDEV_NAME} to ${FLASH_MOUNTPOINT_LEGATO}"
        return ${SWI_OK} # Mounting legato partition is not compulsory for the system to boot
    fi
}

# Unmount user0 Legato "backup" partition. For details take look at the 'start'
# related method above.
mount_early_legato_stop()
{
    local ret=${SWI_OK}
    local mntpt=${FLASH_MOUNTPOINT_LEGATO}
    local dm_device_name=${DM_LGT_NOD_NAME}
    local le_part_name=${LEGATO_MTDEV_NAME}
    local mtd_dev_num=
    local ubi_device=
    local dm_verity_active=

    DS_LINUX_SUB_SYSTEM_FLAG=${DS_SYSTEM_1_FLAG}

    if [ ! -e "$mntpt/start" ]; then
        return ${ret}
    fi

    if [ -x /usr/bin/swidssd ]; then
        /usr/bin/swidssd read linux
        DS_LINUX_SUB_SYSTEM_FLAG=$?
    fi

    if [ $DS_LINUX_SUB_SYSTEM_FLAG -eq $DS_SYSTEM_2_FLAG ]; then
        le_part_name=${le_part_name}2
    fi

    # Legato file system is ubi + squashfs and working on DM-Verity device
    if [ ! -z "$dm_device_name" ]; then
        dm_verity_active=$( mount | grep "${mntpt}" | grep "/dev/mapper/${dm_device_name}" )
    fi

    # Legato file system is ubi + squashfs and working on UBI device
    ubi_device=$( mount | grep "${mntpt}" | grep "type squashfs" | \
                   grep "ubiblock" )

    # There is nothing we can do if umount fails, so do not check
    # the result of the operation. The same is true for ubidetach.
    umount -l ${mntpt}

    # Remove Dm-verity device
    if [ ! -z "${dm_verity_active}" ] ; then
        veritysetup remove ${dm_device_name}
    fi

    # Detach UBI device
    if [ ! -z "${ubi_device}" ] || [ ! -z "${dm_verity_active}" ] ; then
        get_mtdpart_dev_num ${le_part_name}
        mtd_dev_num=$?
        if [ ! ${mtd_dev_num} -eq $SWI_ERR_MAX ] ; then
            ubidetach -m ${mtd_dev_num}
        fi
    fi

    return ${ret}
}

# Mount userrw file system using UBIFS.
mount_early_userrw_start()
{
    local mtd_part_name=${USERRW_MTDEV_NAME}
    local mntpt=${USERRW_MTDEV_MOUNTPOINT}
    local mtd_dev_num=

    if [ -z "$mntpt" ]; then
        return ${SWI_OK}
    fi

    if [ -z "$mtd_part_name" ]; then
        swi_log "Userrw part name does not exist"
        return ${SWI_OK}
    fi

    swi_log "Mounting ${mtd_part_name} file system as UBIFS"
    # Try to mount existing UBIFS partition first.
    mount_ubifs_multi_mount_options ${mtd_part_name} \
                                    ${mntpt} \
                                    ${UBI_USERRW_DEVNUM} \
                                    ${UBI_USERRW_VOLNUM}
    if [ $? -eq ${SWI_OK} ] ; then
        swi_log "${mtd_part_name} mounted to ${mntpt}"
        return ${SWI_OK}
    fi

    # That did not work, so we need to force this partition to be single
    # volume UBIFS .
    swi_log "Formatting ${mtd_part_name} as UBIFS partition"
    create_single_ubi_vol ${mtd_part_name} ${UBI_USERRW_DEVNUM} \
                          ${UBI_USERRW_VOLNUM} ${UBI_USERRW_VOLNAME}
    if [ $? -ne ${SWI_OK} ] ; then
         # UBI volume creation failed
         swi_log "Failed formatting ${mtd_part_name}"
         return ${SWI_ERR}
    fi

    # Now we mount UBIFS volume created above.
    mount_ubifs_multi_mount_options ${mtd_part_name} \
                                    ${mntpt} \
                                    ${UBI_USERRW_DEVNUM} \
                                    ${UBI_USERRW_VOLNUM}
    if [ $? -ne ${SWI_OK} ] ; then
        # UBI volume creation failed
        swi_log "Failed mounting ${mtd_part_name} to ${mntpt}"
        return ${SWI_ERR}
    fi

    # user partition is ubifs now.
    swi_log "${mtd_part_name} mounted to ${mntpt}"

    return ${SWI_OK}
}

# Unmount userrw file system.
mount_early_userrw_stop()
{
    local mntpt=${USERRW_MTDEV_MOUNTPOINT}
    local is_ubifs=
    local mtd_dev_num=

    is_ubifs=$( grep -w "${USERRW_MTDEV_MOUNTPOINT} ubifs" /proc/mounts )

    # There is nothing we can do if umount fails, so do not check
    # the result of the operation. The same goes for ubidetach.
    umount -l ${mntpt}
    if [ -n "${is_ubifs}" ] ; then
        get_mtdpart_dev_num ${USERRW_MTDEV_NAME}
        mtd_dev_num=$?
        if [ ! ${mtd_dev_num} -lt 0 ] ; then
            # detach takes care of the block device as well.
            ubidetach -m ${mtd_dev_num}
        fi
    fi

    return ${SWI_OK}
}

# Early mount pseudo file systems. It is not necessary to unmount
# these before rebooting.
mount_early_pseudo()
{
    local ret=0
    local kvers=`uname -r | cut -f 1 -d .`

    # mount mdev.
    mount -t tmpfs mdev /dev -o rw,relatime,size=${DEVDIR_SIZE},mode=0755,smackfsdef=*

    # Show mqueue stuff.
    mkdir -p /dev/mqueue
    mount -t mqueue none /dev/mqueue -o smackfsdef=*

    # Create multiplexor device
    mknod -m 666 /dev/ptmx c 5 2

    # mount devpts for consoles and such.
    mkdir -p /dev/pts
    # mount -t devpts devpts /dev/pts
    mount -t devpts none /dev/pts -o mode=0620,gid=5,smackfsdef=*

    # DM, FIXME: Restrict the size of this volume.
    # Mount shared memory.
    mkdir -p /dev/shm
    mount -t tmpfs tmpfs /dev/shm -o mode=0777,nodev,nosuid,noexec,smackfsdef=*

    # Mount smackfs on standard location. If standard mount point is not there,
    # most likely, SMACK security is not enabled, and we'll skip it.
    if [ -d /sys/fs/smackfs ] ; then
        echo "${this_e}: Mounting SMACK security pseudo fs..."
        mount -t smackfs smackfs /sys/fs/smackfs
        if [ $? -ne 0 ] ; then
            # If SMACK pseudo file system failed to mount, there is nothing
            # much we could do. However, boot should continue.
            echo "${this_e}: Failed to mount SMACK security pseudo fs."
        else
            # This thing is mounted, add the rules. If we cannot add the rules
            # there is really nothing we could do, so log the problem, and
            # continue booting up.
            add_system_smack_exceptions
            if [ $? -ne 0 ] ; then
                echo "${this_e}: Failed to add system SMACK exceptions."
                umount /sys/fs/smackfs >/dev/null 2>&1
            fi
            add_system_smack_rules
            if [ $? -ne 0 ] ; then
                echo "${this_e}: Failed to add system SMACK rules."
                umount /sys/fs/smackfs >/dev/null 2>&1
            fi
        fi
    fi

    if [ $kvers -lt 4 ] ; then
        # Kick hotplugging and start mdev.
        echo "/sbin/mdev" > /proc/sys/kernel/hotplug
        /sbin/mdev -s
    else
        # Launch mdev as daemon to speed up device detection
        echo "" > /proc/sys/kernel/hotplug
        /sbin/mdev -sd
    fi
}

mount_early_other()
{
    local ret=0

    # DM, FIXME: Restrict the size of this volume.
    # Need /run to be volatile.
    mount -t tmpfs tmpfs /run -o mode=0755,nodev,nosuid,noexec,strictatime,smackfsdef=_

    # DM, FIXME: Restrict the size of this volume.
    # Need /var to be volatile.
    mount -t tmpfs tmpfs /var -o mode=0755,nodev,nosuid,noexec,strictatime,smackfsdef=_

    # Do not restrict the size this file system.
    mount -t tmpfs tmpfs /tmp -o mode=0755,nodev,nosuid,noexec,strictatime,smackfsdef=_

    return ${ret}
}

# Necessary early dirs
mount_early_create_dirs()
{
    local ret=0

    mkdir -p /var/run/dbus
    mkdir -p /var/lock/subsys
    mkdir -p /var/log
    mkdir -p /var/lib/urandom
    if [ -L /etc/resolv.conf ]; then
        # if /etc/resolv.conf is a soft-link, that implies /etc/ is not
        # writeable (and IMA-enabled build is one of the cases). we then need to
        # create the destination file for the link.
        touch `readlink /etc/resolv.conf`
    fi

    return ${ret}
}

# Set timezone. This method is in mount_early, because
# we are mounting various files.
mount_early_set_timezone()
{
    local ret=${SWI_OK}
    local timezone=""
    local localtime=""
    local timezone_files_root=/usr/share/zoneinfo
    local real_localtime=${timezone_files_root}/localtime

    # This is only going to work if /etc/timezone exists
    if [ ! -f /etc/timezone ] ; then
        swi_log "/etc/timezone does not exist, not setting timezone"
        return ${SWI_OK}
    fi

    # If /etc/localtime is not softlink, nothing we could do.
    if [ ! -L /etc/localtime ] ; then
        swi_log "/etc/localtime does not exist, not setting timezone"
        return ${SWI_OK}
    fi

    # Also, /etc/localtime must point to proper timezone file.
    localtime=$( readlink -f /etc/localtime )
    if [ "x${localtime}" != "x${real_localtime}" ] ; then
        # We are unable to perform this operation, but can continue.
        swi_log "/etc/localtime is invalid, not setting timezone"
        return ${SWI_OK}
    fi

    # See what the timezone is. This will be the name of the file
    # in /usr/share/zoneinfo .
    timezone=$( cat /etc/timezone )
    swi_log "Using timezone ${timezone}..."

    # Now, set proper timezone. If this operation fails, it is an error.
    mount --bind ${timezone_files_root}/${timezone} ${real_localtime}
    if [ $? -ne 0 ] ; then
        swi_log "Moounting of ${timezone_files_root}/${timezone} failed."
        ret=${SWI_ERR}
    fi

    return ${ret}
}

mount_early_unset_timezone()
{
    local real_localtime=${timezone_files_root}/localtime

    # Do not care about the result.
    umount -l ${real_localtime} &>/dev/null
    return ${SWI_OK}
}

# Add SMACK netlabel and ipv6host exceptions to grant applications
# permission to communicate with the Internet via IPv4 and IPv6.
# Reference: kernel.org smack admin-guide.
add_system_smack_exceptions()
{
    local smack_net_label=/sys/fs/smackfs/netlabel
    local smack_ipv6_host=/sys/fs/smackfs/ipv6host
    # !TODO: Allow only a specific label. (Need change in Legato as well).
    local single_label="@" # internet, access to all.
    local host_ip="0.0.0.0/0" # all
    local host_ip6="0:0:0:0:0:0:0:0/0" # all

    # netlabel exceptions
    local rule="127.0.0.1 -CIPSO"
    echo "${rule}" > ${smack_net_label}
    if [ $? -ne 0 ]; then
        echo "${this_e}: Error loading system SMACK netlabel exception: ${rule}."
        return ${SWI_ERR}
    fi
    rule="${host_ip} ${single_label}"
    echo "${rule}" > ${smack_net_label}
    if [ $? -ne 0 ]; then
        echo "${this_e}: Error loading system SMACK netlabel exception: ${rule}."
        return ${SWI_ERR}
    fi

    # IPv6 host exceptions
    rule="${host_ip6} ${single_label}"
    echo "${rule}" > ${smack_ipv6_host}
    if [ $? -ne 0 ]; then
        echo "${this_e}: Error loading system SMACK IPv6 host exception: ${rule}."
        return ${SWI_ERR}
    fi
}

# Add SMACK rules considered to be system related.
# All the rules must be located in /etc/smack/accesses, because
# we could also use smack userland tools to load the rules from
# this file (if we choose to do so later on).
add_system_smack_rules()
{
    local smack_rules_src=/etc/smack/accesses
    local smack_rules_dst=/sys/fs/smackfs/load2
    local smack_delay=
    local ret=${SWI_OK}

    if [ ! -f ${smack_rules_src} ] ; then
        echo "${this_e}: Cannot find ${smack_rules_src}."
        return ${SWI_ERR}
    fi

    if [ ! -f ${smack_rules_dst} ] ; then
        echo "${this_e}: Cannot find ${smack_rules_dst}."
        return ${SWI_ERR}
    fi

    (   set -e; \
        while read -r -u 10 i; do \
            if ! echo "$i" | grep -q -e '^#' -e '^ *$'; then \
                if echo $i; then \
                    sleep ${smack_delay:-0}; \
                else \
                    echo "${this_e}: Invalid line in ${smack_rules_src}: $i" >&2; \
                    return ${SWI_ERR}; \
                fi; \
            fi; \
        done ) 10<${smack_rules_src} >${smack_rules_dst}
    if [ $? -ne 0 ]; then
        echo "${this_e}: Error loading system SMACK rules."
        ret=${SWI_ERR}
    fi

    return ${ret}
}

# Chooser.
mount_early_start()
{
    local ret=0

    # list of methods to execute
    local method_list_essential=""

    # Mount essential volumes only if we are not relying on the initramfs
    if grep 'root=' /proc/cmdline > /dev/null; then
        method_list_essential="
                               mount_early_pseudo
                               mount_early_other
                               mount_early_create_dirs
                               mount_early_set_timezone
                              "
    fi

    local method_list="
                       yaffs2_kern_supported_init
                       mount_early_user_start
                       mount_early_legato_start
                       mount_early_userrw_start
                      "

    for method in ${method_list_essential} ${method_list} ; do
        echo "${this_e}: Executing ${method}... "
        ${method}
        if [ $? -ne 0 ] ; then return 1 ; fi
    done

    return ${ret}
}

# Stop all.
mount_early_stop()
{
    local ret=0

    # list of methods to execute
    local method_list="
                       mount_early_user_stop
                       mount_early_legato_stop
                       mount_early_userrw_stop
                       mount_early_unset_timezone
                      "

    for method in ${method_list} ; do
        echo "${this_e}: Executing ${method}... "
        ${method}
        if [ $? -ne 0 ] ; then return 1 ; fi
    done

    return ${ret}
}


#
# Execution starts here.
#
case "$1" in
    start)
        mount_early_start
    ;;

    stop)
        mount_early_stop
    ;;

    *)
        echo "Usage: ${this_e} {start | stop}"
        exit 1
    ;;
esac

exit 0

