#!/usr/bin/env bash
#
#       oemntrw
#       Version 1.0
#
# This is an automation tool for the EMAC OE 5.0 SDK
#
# Mounts the EMAC OE filesystem to Read Write mode
#
# Usage: oemntrw [OPTION] 
#
# kyoungmeyer@emacinc.com
# September 9, 2013
#
# Copyright (C) 2013, EMAC, Inc.
# All rights reserved.      
#

#TOOLS
MOUNT="/usr/bin/env mount"
######

readonly PROGNAME=$(basename "$0")
readonly LOCKFILE_DIR=/tmp
readonly LOCK_FD=200

Version="1.2"
version () { 
	echo "$(basename $0) (EMAC OE Automation Tools) Version $Version"
	echo "Copyright (C) 2013-2014 EMAC, Inc.  All rights reserved."; 
}

help () {
    echo
    echo "Usage: oemntrw [OPTION] [-k unique-identifier]"
    echo "Mount the EMAC OE filesystem to Read-Write mode"
    echo
    echo "Options:"
    echo "  -r      Remounts the root filesystem read-only"
    echo "  -t      Toggles the write state of the root filesystem between read-write and read-only"
    echo "  -i      Returns the write state of the root filesystem. Returns 0 for read-write" 
    echo "          and 1 for read-only"
    echo "  -k      Stores the current write state of the filesystem to a unique file, sets the"
    echo "          filesystem read-write, and retrieves this state next time the program is run"
    echo "          with this flag and unique identifier."
    echo "  -l      List the unique identifiers that are active."
    echo "  -d      Restore read-write state to what it was before using the -k flag."
    echo "  -v      Display version info and exit"
    echo "  -h      Display this help and exit"
    echo
    version
    echo
    exit 0
}
showerr()
{
    printf "\e[01;31mERROR: \e[01;37m${*}\e[0m\n"
    exit 9
}
check_tool()
{
    $1 > /dev/null 2>&1

    if [ $? == "127" ]
    then
        showerr "${2} command not found in path.  Exiting."
    fi
}
check_tools()
{
    check_tool "$MOUNT" "mount"
}

check_tools

lock() {
    local prefix=$1
    local fd=${2:-$LOCK_FD}
    local lock_file=$LOCKFILE_DIR/$prefix.lock

    # create lock file
    eval "exec $fd>$lock_file"

    # acquire the lock
    flock -n $fd \
        && return 0 \
        || return 1
}

write-stat()
{
    if [[ ! -w / ]]; then
        return 1 
    else
        return 0
    fi

}
mount-rw()
{
    $MOUNT -o remount,rw /
}
mount-ro()
{
    $MOUNT -o remount,ro /
}
toggle()
{
    if write-stat; then
        mount-ro
    else
        mount-rw
    fi
}
inquire()
{
    if write-stat; then
        #echo "Root filesystem is mounted read-write"
        return 0
    else
        #echo "Root filesystem is mounted read-only"
        return 1
    fi
}
keep-state()
{
    lock $PROGNAME \
        || for ((i=1; i<=20; i++));do usleep 500; lock $PROGNAME && break; done \
        || showerr "Only one instance of $PROGNAME can run at one time."
    
    GEN_FILE_NAME="/tmp/.general.oemntrw-state.lock.tmp"
    FILE_NAME="/tmp/.oemntrw-state."$PROCESS".tmp"
    if write-stat; then
        CURRENT_STAT="RW" 
    else
        CURRENT_STAT="RO"
    fi
    if [[ -f $GEN_FILE_NAME ]]; then
        OPEN_FILES=$(find /tmp/ -name ".oemntrw-state.*.tmp" | wc -l)
        if [[ $OPEN_FILES -eq 1 ]]; then
            if [[ -f $FILE_NAME ]]; then
                source $GEN_FILE_NAME
                if [[ $SAVE_STAT == "RW" ]]; then
                    mount-rw
                    rm $FILE_NAME $GEN_FILE_NAME
                elif [[ $SAVE_STAT == "RO" ]]; then
                    mount-ro
                    rm $FILE_NAME $GEN_FILE_NAME
                else
                    showerr "Saved write state format is wrong. No change made"
                fi
            else
                touch $FILE_NAME
                echo "SAVE_STAT=$CURRENT_STAT" >> $FILE_NAME
            fi
        elif [[ $OPEN_FILES -gt 1 ]]; then
            if [[ -f $FILE_NAME ]]; then
                rm $FILE_NAME
            else
                touch $FILE_NAME
                echo "SAVE_STAT=$CURRENT_STAT" >> $FILE_NAME
            fi
        else
            #echo "How did you get here?"
            source $GEN_FILE_NAME
            if [[ $SAVE_STAT == "RW" ]]; then
                mount-rw
                rm $FILE_NAME $GEN_FILE_NAME
            elif [[ $SAVE_STAT == "RO" ]]; then
                mount-ro
                rm $FILE_NAME $GEN_FILE_NAME
            else
                showerr "Saved write state format is wrong. No change made"
            fi
        fi
    else
        touch $GEN_FILE_NAME
        echo "SAVE_STAT=$CURRENT_STAT" >> $GEN_FILE_NAME
        touch $FILE_NAME
        echo "SAVE_STAT=$CURRENT_STAT" >> $FILE_NAME
    fi
}
list-keep()
{   
    if [[ -f /tmp/.general.oemntrw-state.lock.tmp ]]; then
        echo "The following identifiers have been used to keep a read-write state:"
        for keep in $(find /tmp/ -name ".oemntrw-state.*.tmp"); do
            filename=$(basename $keep)
            firstpart="${filename%.*}"
            procname="${firstpart##*.}"
            echo -e "\t$procname"
        done
    else
        echo "No identifiers are active"
    fi
}
revert-default()
{
    if [[ -f /tmp/.general.oemntrw-state.lock.tmp ]]; then
        echo "Resetting read-write state to default..."
        for remove in $(find /tmp/ -name ".oemntrw-state.*.tmp"); do
            filename=$(basename $remove)
            firstpart="${filename%.*}"
            procname="${firstpart##*.}"
            PROCESS=$procname
            keep-state
        done
    else
        echo "No identifiers are active"
    fi
}

COMMAND="mount-rw"
while getopts ":k:rtildvh" opt; do
  case $opt in
    r   ) COMMAND="mount-ro";;
    t   ) COMMAND="toggle";;
    i   ) COMMAND="inquire";;
    k   ) COMMAND="keep-state"; PROCESS="$OPTARG";;
    l   ) COMMAND="list-keep";;
    d   ) COMMAND="revert-default";;
    v   ) version; exit 0;;
    h   ) help; exit 0;;
    \?  ) echo "Invalid option: -$OPTARG" >&2; exit 1;;
    :   ) echo "Option -$OPTARG requires an argument" >&2; help; exit 1;;
  esac
done

if [[ $UID -ne 0 ]]; then
    showerr "This program must be run as root" 1>&2
    exit 1
fi

${COMMAND}
