#!/bin/bash
#
# LXC device access permission setup script
# This will be called by the lxc_hook and takes vm_name as it's input argument.
#
# This script does the basic initialization of LXC infra
# Copyright (c) 2014-2015 by Cisco Systems, Inc.
# All rights reserved.

set -m

BOOTSTRAP_FILE="/etc/init.d/calvados_bootstrap.cfg"
source $BOOTSTRAP_FILE

SPIRIT_FUNCTIONS="/etc/init.d/spirit-functions"
source $SPIRIT_FUNCTIONS

DEV_LIST_GET_FILE="/etc/init.d/devlist_get"
source $DEV_LIST_GET_FILE

# Thie script would be executed only if VIRT_METHOD=lxc on host.
if [[ $VIRT_METHOD != "lxc" ]]; then
    exit 0
fi

vmtype=`cat /proc/cmdline | sed 's/^.*vmtype=//' | cut -d" " -f1`
if [[ "$vmtype" != "hostos" ]]; then
    exit 0
fi

#
# It can take a couple of seconds for the cgroup tree to be created.
# Pause briefly to allow for this.
#
function wait_for_cgroup() {
    local COUNT=0
    local MAX=10

    while [ $COUNT -lt $MAX ]
    do
        if [ -f $devallowfile ]
        then
            return
        fi

        COUNT=`expr $COUNT + 1`
    done

    echo "$0: Failed to find $devallowfile"
}

#if [ ! -f $devallowfile ]
#then
#    wait_for_cgroup
#fi

prog="dev-allow"
RETVAL=0

function allow_device(){
    abspath=$1
    majornum=""
    minornum=""

    if [ -e $abspath ]
    then
        #stat returns major and minor number in hex
        #Its being converted to decimal as expected
        # by /dev/cgroup/devices/libvirt/lxc/devices.allow
        majornum=$(printf "%d" `stat -L -c 0x'%t' $abspath`)
        minornum=$(printf "%d" `stat -L -c 0x'%T' $abspath`)
        case `stat -L -c '%F' $abspath | cut -d" " -f1` in
        "block"|"Block")
            if [ -e $devallowfile ]; then
            # Stores b (block) Major Number:Minor Number rwm
            # (read write memory) to devallowfile
            # mapper devices can be created later so minor number
            # is passed as * for generic perpose
            case $abspath in
                *mapper*)
                    echo "b $majornum:* rwm" > $devallowfile
                    echo "$abspath b $majornum $minornum" >> $devlistdata
                    ;;
                *)
                    echo "b $majornum:$minornum rwm" > $devallowfile
                    echo "$abspath b $majornum $minornum" >> $devlistdata
                    ;;
            esac
            else
                echo "device allow ($devallowfile) file not exist"
                RETVAL=1;
            fi
        ;;
        "character"|"Character")
            if [ -e $devallowfile ]; then
            # Stores c (character)  Major Number:Minor Number rwm
            # (read write memory) to devallowfile
            # uio devices can be created later so minor number is
            # passed as * for generic purpose
            case $abspath in
                *uio*)
                    echo "c $majornum:* rwm" > $devallowfile
                    echo "$abspath c $majornum $minornum" >> $devlistdata
                    ;;
                *mapper*)
                    echo "c $majornum:* rwm" > $devallowfile
                    ;;
                *)
                    echo "c $majornum:$minornum rwm" > $devallowfile
                    echo "$abspath c $majornum $minornum" >> $devlistdata
                    ;;
            esac
            else
                echo "device allow ($devallowfile) file not exist"
                RETVAL=1;
            fi
        ;;
        esac
    fi
}
readonly -f allow_device

function read_devlist(){
    index=0
    #Reading line by line from input file "devlistconf"
    if [ -f $devlistconf ]; then
        while read line; do
            #Storing each line as an array element
            devarray[$index]=$line
            index=$((index+1))
        done < "$devlistconf"

        for (( i=0; i<${#devarray[@]}; i++ )); do
            #Stripping out any spaces in the array element
            devarray[i]=${devarray[i]//[[:space:]]/}

            #Splitting the array element using "'" as Field separator
            IFS=, read -a devices <<< "${devarray[i]}"

            for (( j=0; j<${#devices[@]}; j++ )); do
                #Each path can be given with wild charater, so looping with all the probabilities
                for file in ${devices[j]}
                do
                    allow_device $file
                done
            done
        done
    else
        echo "device list config file ($devlistconf) not present"
        RETVAL=1
    fi
}
readonly -f read_devlist
start()
{
    echo "Starting $prog"
    if [ -f $devlistdata ]; then
        rm -f $devlistdata
    fi

    # Since containers do not have device creation capability, we pass
    # the list of devices accessible from the container by adding to the
    # devices cgroup subsystem
    read_devlist
}

stop()
{
    echo "Stoping $prog"
}

if [ "$1" != "start" ]; then
   devlist_get "$1" devlistconf devallowfile devlistdata devlisttarget RETVAL
else
   # host bootup invokes this script with 'start' argument so this is a nop
   RETVAL=1
fi

if [[ "$RETVAL" -eq 0 ]]; then
    start
    cp "$devlistdata" "$devlisttarget"
fi
exit $RETVAL
