# vim: syntax=sh ts=4 sts=4 sw=2:et
# Copyright 2012 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# 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.

function tmpfs_check() {
  [ "$DIB_NO_TMPFS" == "0" ] || return 1
  [ -r /proc/meminfo ] || return 1
  total_kB=$(awk '/^MemTotal/ { print $2 }' /proc/meminfo)
  [ $total_kB -lt $((4*1024*1024)) ] || return 0
  echo "Not enough RAM to use tmpfs for build. ($total_kB < 4G)"
  return 1
}

function mk_build_dir () {
  export TMP_BUILD_DIR=$(mktemp -t -d --tmpdir=${TMP_DIR:-/tmp} image.XXXXXXXX)
  [ $? -eq 0 ] || die "Failed to create tmp directory"
  if tmpfs_check ; then
    sudo mount -t tmpfs tmpfs $TMP_BUILD_DIR
  fi
  sudo chown $(id -u):$(id -g) $TMP_BUILD_DIR
  trap cleanup EXIT
  echo Building in $TMP_BUILD_DIR
  export TMP_IMAGE_PATH=$TMP_BUILD_DIR/image.raw
  export TMP_HOOKS_PATH=$TMP_BUILD_DIR/hooks
}

function save_image () {
    # TODO: this really should rename the old file
    if [ -f  $1 ] ; then
       echo "Old Image file Found REMOVING"
       rm -f $1
    fi

    cp $TMP_IMAGE_PATH $1
    cleanup_dirs
    # All done!
    trap EXIT
    echo "Image file $1 created..."
}

function generate_hooks () {
  mkdir -p $TMP_HOOKS_PATH
  for _ELEMENT in $IMAGE_ELEMENT ; do
    for dir in $(echo $ELEMENTS_PATH | tr ":" " ") ; do
       [ -d $dir/$_ELEMENT ] || continue
      cp -t $TMP_HOOKS_PATH -a $dir/$_ELEMENT/* ;
      break
    done
  done
}

# Call the supplied break-in routine if the named point is listed in the break
# list.
# $1 the break point.
# $2.. what to call if a break is needed
function check_break () {
  if echo "$break" | egrep -e "(,|^)$1(,|$)" -q; then
    echo "Starting debug shell. Exit to resume building." >&2
    echo At stage $1 >&2
    shift
    "$@"
    echo "Resuming" >&2
  fi
}

# Check that a real element has been chosen (prevents foot-guns)
function check_element () {
  [ -d $TMP_HOOKS_PATH ] || generate_hooks
}

# Run a hook, looking for a regex in its stdout, and eval the matched lines.
# $1 is the hook to run
# $2 is the regex to look for
function eval_run_d () {
  local TEMP=`run_d $1`
  echo "$TEMP"
  if [ `echo "$TEMP" | grep -s "$2"` ]; then
      TEMP=`echo "$TEMP" | grep "$2"`
      eval "$TEMP"
  fi
}

# Usage: map_nbd $image
# Returns nbd device path
function map_nbd {
    (lsmod | grep '^nbd ') || sudo modprobe nbd max_part=16

    if [[ $(qemu-nbd --help | grep cache) == *writeback* ]] ; then
        CACHE="--cache=writeback"
    else
        echo "Warning: qemu-nbd without --cache=writeback is /slow/."
        CACHE=""
    fi
    NBD_DEV=
    for i in `seq 0 15`; do
        if [ ! -e /sys/block/nbd$i/pid ]; then
            NBD_DEV=/dev/nbd$i
            # Connect to nbd and wait till it is ready
            sudo qemu-nbd -c $NBD_DEV $CACHE $1
            if ! timeout 60 sh -c "while ! [ -e /sys/block/nbd$i/pid ]; do sleep 1; done"; then
                echo "Couldn't connect $NBD_DEV"
                exit 1
            fi
            break
        fi
    done
    if [ -z "$NBD_DEV" ]; then
        echo "No free NBD slots"
        exit 1
    fi
}

# Delete and unmount the working dir used in extracting kernel/initrd
function unmount_qcow_image () {
    sudo umount $WORK_DIR || true
    sudo qemu-nbd -d $NBD_DEV || true
    sudo rm -rf $WORK_DIR

    trap - SIGHUP SIGINT SIGTERM EXIT
}

function mount_qcow_image() {
    trap unmount_qcow_image SIGHUP SIGINT SIGTERM EXIT

    WORK_DIR=$(mktemp -d)
    map_nbd $1
    if [ -e "${NBD_DEV}p1" ]; then
       sudo mount ${NBD_DEV}p1 $WORK_DIR
    else
       sudo mount ${NBD_DEV} $WORK_DIR
    fi
}

function cleanup_dirs () {
    sudo rm -rf $TMP_BUILD_DIR/built
    sudo rm -rf $TMP_BUILD_DIR/mnt
    sudo umount -f  $TMP_BUILD_DIR || true
    rm -rf $TMP_BUILD_DIR
}

# Run a directory of hooks outside the target.
function run_d() {
    check_element
    check_break before-$1 bash
    if [ -d ${TMP_HOOKS_PATH}/$1.d ] ; then
      run-parts ${TMP_HOOKS_PATH}/$1.d
    fi
    check_break after-$1 bash
}

function detach_loopback() {
    local loopdev=$1
    # loopback dev may be tied up a bit by udev events triggered by partition events
    for try in $(seq 10 -1 1) ; do
        if sudo losetup -d $loopdev ; then
            return 0
        fi
        echo $loopdev may be busy, sleeping up to $try more seconds...
        sleep 1
    done
    echo Gave up trying to detach $loopdev
    return 1
}

function arg_to_elements() {
  for arg do IMAGE_ELEMENT="$IMAGE_ELEMENT $arg" ; done

  if [ "$SKIP_BASE" != "1" ]; then
    IMAGE_ELEMENT="base $IMAGE_ELEMENT"
  fi
  echo "Building elements: $IMAGE_ELEMENT"
  echo "If prompted for sudo, install sudoers.d/img-build-sudoers into /etc/sudoers.d and restart the build."

  IMAGE_ELEMENT=$($SCRIPT_HOME/element-info --expand-dependencies $IMAGE_ELEMENT)

  echo "Expanded element dependencies to: $IMAGE_ELEMENT"
}