#!/bin/bash
# Copyright 2012 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2012 NTT DOCOMO, INC.
#
# 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 fullpath() {
  local f=$1
  if [ "${f#/}" = "$f" ]; then
    echo `pwd`/"$f"
  else
    echo "$f"
  fi
}

function create_ramdisk_base () {
  echo "Creating base system"

  mkdir -p "${TMP_MOUNT_PATH}/"{bin,lib/modules,etc/udev}
  ln -s bin "$TMP_MOUNT_PATH/sbin"
  # cjk adding for discovery support
  mkdir -p "${TMP_MOUNT_PATH}/"{lib/udev/rules.d,var/{lib/dhcp,run}}

  case "$DISTRO_NAME" in
    fedora|rhel|rhel7|opensuse)
      mkdir -p "$TMP_MOUNT_PATH/usr"
      ln -s ../lib "$TMP_MOUNT_PATH/usr/lib"
      if [[ "`uname -m`" =~ x86_64|ppc64 ]]; then
        ln -s lib "$TMP_MOUNT_PATH/lib64"
      fi
      ;;
  esac

  if [ -e $LIB_UDEV/rules.d/50-firmware.rules ]; then
    cp -a "$LIB_UDEV/rules.d/50-firmware.rules" "$TMP_MOUNT_PATH/lib/udev/rules.d"
  fi

  cp -a "$LIB_UDEV/rules.d/80-drivers.rules" "$TMP_MOUNT_PATH/lib/udev/rules.d"

  if [ -a $LIB_UDEV/firmware ]; then
    cp -a "$LIB_UDEV/firmware" "$TMP_MOUNT_PATH/lib/udev"
  fi

  # cjk adding dhclient for hwdiscovery support
  # dhclient scripts on some distros appear in different places, copy any we find
  for FILE in /sbin/dhclient-script /usr/sbin/dhclient-script /etc/sysconfig/network-scripts/* /etc/rc.d/init.d/functions /etc/init.d/functions ; do
    if [ -f $FILE ] ; then
      mkdir -p $(dirname $TMP_MOUNT_PATH/$FILE)
      cp $FILE $TMP_MOUNT_PATH/$FILE
    fi
  done
  # /var/lib/dhclient is a directory on Fedora
  if [ -d "/var/lib/dhclient" ] ; then
    mkdir -p "$TMP_MOUNT_PATH/var/lib/dhclient"
  fi

  mkdir -p "$TMP_MOUNT_PATH/etc/modprobe.d"
  # The directory may or may not exist in the image. If the directory exists in
  # the image, all the files under it should get copied to the ramdisk.
  if [ -d "/etc/modprobe.d/" ] ; then
      find /etc/modprobe.d -name '*.conf' -type f -exec cp -a {} "$TMP_MOUNT_PATH/etc/modprobe.d" \;
  fi
  echo "blacklist evbug" > "$TMP_MOUNT_PATH/etc/modprobe.d/blacklist-dib-ramdisk.conf"

  # cjk adding for hwdiscovery support
  touch "$TMP_MOUNT_PATH/etc/fstab"

  mkdir -p "$TMP_MOUNT_PATH/etc/udev"
  cat >"$TMP_MOUNT_PATH/etc/udev/udev.conf" <<EOF

udev_root="/dev"
udev_rules="/lib/udev/rules.d"
udev_log="no"
EOF

  generate_hooks
  TARGET_ROOT=$TMP_MOUNT_PATH run_d root
}

function copy_required_libs() {
  set +e
  ldd_out=`ldd "$1"`
  local ret_code=$?
  set -e
  if [ $ret_code -ne 0 ]; then
    return
  fi
  local IFS="
"

  # Patterns of output of ldd
  #
  # 1. name to real path
  #     libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f095e784000)
  # 2. only path
  #	    /lib64/ld-linux-x86-64.so.2 (0x00007f095ef79000)
  # 3. path to path
  #	    /lib64/ld-linux-x86-64.so.2 => /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 (0x00007facff857000)
  # 4. name to empty (vdso)
  #	    linux-vdso.so.1 =>  (0x00007fff0c5ff000)
  #    or, in some setups:
  #	    linux-vdso.so.1 (0x00007fff0c5ff000)

  for i in `echo "$ldd_out" | sed -e 's/^\t*//'`; do
    local ref=$( echo "$i" | awk -F '[ ]' '{print $1}')
    local real=$( echo "$i" | awk -F '[ ]' '$2 == "=>" {print $3}
                                            $2 != "=>" {print $1}')
    if [ -z "$real" ] || [[ "$real" != /* ]]; then
      continue
    fi
    if [ "$ref" = "${ref#/}" ]; then
      ref=/lib/$ref
    fi
    dest=/lib/`basename "$real"`
    cp -Ln "$real" "$TMP_MOUNT_PATH/$dest"
    # Create a symbolic link if the shared library is referred
    # by the different name
    if [ "$ref" != "$dest" ]; then
      local link_path=$TMP_MOUNT_PATH/$ref
      if ! [ -e "$link_path" -o -L "$link_path" ]; then
        mkdir -p $(dirname "$link_path")
        ln -s "$dest" "$link_path"
      fi
    fi
  done
}

function populate_lib () {
  echo "Populating /lib"

  # find udevd
  UDEVD=
  for f in /sbin/udevd /lib/udev/udevd /lib/systemd/systemd-udevd \
          /usr/lib/systemd/systemd-udevd \
          /usr/lib/udev/udevd; do
      if [ -x "$f" ]; then
          UDEVD="$f"
          break
      fi
  done

  UDEV_FIRMWARE=
  if [ -a $LIB_UDEV/firmware ]; then
     UDEV_FIRMWARE="$LIB_UDEV/firmware"
  fi

  for i in "$BUSYBOX" bash lsmod modprobe udevadm \
           wget reboot shutdown $UDEVD $UDEV_FIRMWARE \
           $(cat /etc/dib_binary_deps) ; do
    # Don't take the ip command from busybox, its missing some features
    if busybox_list | grep -v "^ip$" | grep "^$i\$" >/dev/null; then
      continue
    fi
    path=`which $i 2>/dev/null` || path=$i
    if ! [ -x "$path" ]; then
      echo "$i is not found in PATH" 2>&1
      exit 1
    fi
    cp -L "$path" "$TMP_MOUNT_PATH/bin/"
    copy_required_libs "$path"
  done

  if [ -f /dib-signed-kernel-version ] ; then
      . /dib-signed-kernel-version
  fi
  if [ -n "${DIB_SIGNED_KERNEL_VERSION:-}" ]; then
      # Secure kernel module directory does not have efi.signed suffix to
      # kernel version.
      if echo $KERNEL_VERSION | grep -q 'efi.signed'; then
          KERNEL_VERSION=`echo "$KERNEL_VERSION" |sed "s/\.efi\.signed//g"`
      fi
  fi
  cp -a "$MODULE_DIR" "$TMP_MOUNT_PATH/lib/modules/$KERNEL_VERSION"
  echo "Removing kernel framebuffer drivers to enforce text mode consoles..."
  find $TMP_MOUNT_PATH/lib/modules/$KERNEL_VERSION/kernel/drivers/video -name '*fb.ko' -exec rm -v {} +
  if [ -d $FIRMWARE_DIR ]; then
    cp -a "$FIRMWARE_DIR" "$TMP_MOUNT_PATH/lib/firmware"
  fi
}

function busybox_list () {
    # busybox supports --list option since version 1.18
    "$BUSYBOX" --list 2> /dev/null && return
    # for busybox under 1.18 we parse command list from --help output
    scrlet='{ if (go) { print } } /Currently defined functions:/ { go=1 }'
    "$BUSYBOX" --help | awk "$scrlet" | tr ',' '\n' | xargs -n1 echo
}

function populate_busybox () {
  echo "Creating symlinks for busybox binaries"

  for i in $( busybox_list ); do
    if [ -f "$TMP_MOUNT_PATH/bin/$i" ]; then
      echo "skip $i"
      continue
    fi
    ln -s busybox "$TMP_MOUNT_PATH/bin/$i"
  done
}

function populate_init () {
  echo "Installing init"
  cp "$INIT" "$TMP_MOUNT_PATH/init"
  chmod +x $TMP_MOUNT_PATH/init
  for F in "$FUNCTIONS_D"/* ; do
    cp "$F" "$TMP_MOUNT_PATH"
  done

  # Append /init with any element fragments that are present
  TARGET_DIR="/tmp/in_target.d/"
  for _ELEMENT in $(ls $TARGET_DIR/init.d/) ; do
    _FILE="${TARGET_DIR}/init.d/${_ELEMENT}"
    if [ -a $_FILE ]; then
      cat >>$TMP_MOUNT_PATH/init <<EOF

# init fragment from ${_ELEMENT}
EOF
      cat <$_FILE >>$TMP_MOUNT_PATH/init
    fi
  done

  # Add our final steps to /init
  cat <${INIT}-end >>$TMP_MOUNT_PATH/init
}

function finalise_image () {
  echo "Finalising image"
  (cd "$TMP_MOUNT_PATH"; find . | cpio -o -H newc | gzip > "$TMP_IMAGE_PATH" )
}

function populate_udev () {
  echo "Installing udev rules"

  TARGET_DIR="/tmp/in_target.d/"
  for _ELEMENT in $(ls $TARGET_DIR/udev.d/) ; do
    _FILE="${TARGET_DIR}/udev.d/${_ELEMENT}"
    if [ -a $_FILE ]; then
      cp ${_FILE} $TMP_MOUNT_PATH/lib/udev/rules.d/
    fi
  done
}

function find_kernel_version () {
  _TMP=$(ls /boot/vmlinu* | sort | tail -1)
  if [ "$_TMP" == "" ]; then
    echo "Unable to find a suitable kernel" >>/dev/stderr
    exit 1
  fi
  echo ${_TMP##/boot/vmlinu[zx]-}
}