#!/bin/bash
# Copyright 2017 IBM Corp.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
#
### BEGIN INIT INFO
# Provides: zvmguestconfigure
# Default-Start: 2 3 5
# Default-stop: 0 1 4 6
# Required-Start: $syslog
# Should-Start:
# Required-Stop:
# Short-Description: A basic active engine used to initialize and configure vm.
# Description: Reads class x files from the reader and acts based on the type of file.
#              Generate an ISO9660 disk for cloud-init to handle sdk configurations.
#              Files of filetype "disk" cause disks be configured. (deprecated)
#              Other files are used to configure vm when it start up.
### END INIT INFO

###############################################################################
# Authorized senders of configuration files listed here.  Specify a list a
# blank delimited list of userids with each userid in uppercase
# (e.g. "AUTH" or "AUTH AUTH2"), or '*' to indicate all are authorized.
# If nothing is specified then this function will not process any
# configuration files in the reader.
###############################################################################
version=2.0
authorizedSenders='*'

function onlineDevice {
  # @Description:
  #   Brings a Linux device online.
  # @Input:
  #   Device number, e.g. "0.0.000c"
  # @Output:
  #   Return code indicates success or failure
  # @Code:
  device=$1
  local funcName="onlineDevice"
  rc=$(/sbin/chccwdev -e $device > /dev/null; echo $?)
  if (( rc != 0 )); then
    if [[ -e /sbin/cio_ignore ]]; then
      rc=$(/sbin/cio_ignore -r 0.0.$device > /dev/null; echo $?)
      which udevadm &> /dev/null && udevadm settle || udevsettle
    fi
    rc=$(/sbin/chccwdev -e $device > /dev/null; echo $?)
    if (( rc != 0 )); then
      echo "zvmguestconfigure $funcName (Error) Could not activate the virtual device $device"
      return 1
    fi
  fi
  which udevadm &> /dev/null && udevadm settle || udevsettle
  return 0
}

function pullReader {
  # @Description:
  #   Reads class x spool files from the reader if sent by an authorized sender.
  #   Drives special processing functions for files of a specific type.
  #   Files with a file type of:
  #     iso that can be used to setup iso9660 loop device that will be consumed by cloud-init
  #     sh that can be used to execute shell script
  #     doscript that contains a invokeScript.sh which will call the other script in it to do the speicial work

  # @Input:
  #   None
  # @Output:
  #   Return code indicates success if reader was brought online.
  # @Code:
  local funcName="pullReader"
  /sbin/modprobe vmcp

  # Online reader
  rc= onlineDevice "000c"
  if (( rc != 0 )); then
      return $rc
  fi

  # Grab the spool Id, class file name, and file type
  eval records=($(/usr/sbin/vmur li | tail -n +2 | cut -c 1-80 | awk '{print $1":"$2":"$3":"$10":"$11"\n"}' ))

  # Process each spool file that is class "x"
  for record in "${records[@]}"
  do
    record=$(echo $record | tr ":" " ")
    set $record
    originid=$1
    spoolid=$2
    class=$3
    filename=$4
    type=$5

    if [[ $class != "X" ]]; then
      # Spool file is not of the class required for processing by this script.
      continue
    fi

    if [[ $authorizedSenders != "*" ]]; then
      if [[ " $authorizedSenders " != *" $originid "* ]]; then
        # Originator is not authorized to send configuration files.
        continue
      fi
    fi

    if [[ -n $type ]]; then
      file="$filename.$type"
    else
      file=$filename
    fi

    # Receive the spool file
    echo "Downloading record $spoolid: $file"

    if [[ $type == "sh" ]]; then
      # Receiving shell
      rc=$(/usr/sbin/vmur re -f $spoolid $file)
      /bin/bash $file
      rm $file
    # Handle the cfgdrive.iso that punched by openstack nova-zvm-driver
    elif [[ $type == "iso" ]]; then
      rc=$(/usr/sbin/vmur re -f $spoolid $file)
    elif [[ $type == "doscript" ]]; then
      rc=$(/usr/sbin/vmur re $spoolid $file)
      /bin/tar xf $file -C $transportdir
      rm $file
      /bin/bash invokeScript.sh
    fi

    if (( rc != 0 )); then
      echo "zvmguestconfigure funcName (Error) Failed to download record $spoolid"
    fi
  done
  return 0
}

function setupIso {
  # @Description:
  #   Makes an ISO filesystem using the contents of the transport directory and
  #   creates a loop device pointing to the ISO image.  If an "init.sh" script
  #   exists in the transport directory then it is driven.
  # @Input:
  #   None
  # @Output:
  #   None
  # @Code:
  local funcName="setupIso"
  iso="/var/opt/zthin/transport/cfgdrive.iso"
  iso4cloudinit="/var/opt/zthin/cfgdrive.iso"

  # If the ISO filesystem exists then create loop back device pointing
  # to the ISO9660 image
  if [[ -e $iso ]]; then
    mv $iso $iso4cloudinit
  fi
  
  if [[ -e $iso4cloudinit ]]; then
    nextLoopDev=`/sbin/losetup -f`
    if [[ -n $nextLoopDev ]]; then
      /sbin/losetup $nextLoopDev $iso4cloudinit
    fi
  fi

  # Execute init script (if one exists)
  if [[ -e ${transportdir}/init.sh ]]; then
    chmod 755 ${transportdir}/init.sh
    ${transportdir}/init.sh
  fi
}


############################################################################
# Main Code Section
############################################################################
case "$1" in
  start)
    echo "zvmguestconfigure is starting"
    transportdir="/var/opt/zthin/transport"
    rm -Rf $transportdir
    /bin/mkdir -p $transportdir
    cd $transportdir

    if [[ -n "$authorizedSenders" ]]; then
      pullReader
      echo "zvmguestconfigure has successfully processed the reader files."
    else
      echo "zvmguestconfigure is disabled from accepting configuration reader files."
    fi

    setupIso
  ;;

  status)
    if [[ -n "$authorizedSenders" ]]; then
      echo "zvmguestconfigure is enabled to accept configuration reader files from: $authorizedSenders"
    else
      echo "zvmguestconfigure is disabled from accepting configuration reader files."
    fi
  ;;

  version)
    echo "zvmguestconfigure version:" $version
  ;;

  stop|restart|reload|force-reload)
    # Do nothing
  ;;

esac
