# This must be called in a script before set -e because
# /etc/init.d/functions on RedHat is not errexit safe and will exit
# prematurely.

SUSE_RELEASE=/etc/SuSE-release
REDHAT_RELEASE=/etc/redhat-release
UBUNTU_RELEASE=/etc/debian_version

LIBDIR=/usr/lib/vmware-tools

error()
{
   echo "ERROR: $*"
   exit 1
}

#
# We exit on failure because these functions are called within the
# context of vmware_exec, which sets up a trap that causes exit to jump
# back to vmware_exec, like an exception handler. On success, we return
# because our caller may want to perform additional instructions.
#
vmware_load_module() {
   local module=$1
   shift

   # pvscsi shouldn't be unloaded in case it was loaded from an
   # initrd.
   if [ "`isLoaded $module`" = "yes" ] && [ $module != pvscsi ]; then
      /sbin/rmmod $module
   fi

   local release=`uname -r`

   # 2.6 kernels use *.ko, 2.4 use *.o.  Bug #446364.
   local ext=ko
   if echo $release | grep '^2\.4' >/dev/null 2>&1; then
      ext=o
   fi

   local path=/lib/modules/`uname -r`/misc/$module.$ext

   # Prefer kernel versioned modules if they exist.  Currently this is the
   # case for ubuntu as well as user rebuilt kmod source packages.
   if [ -e "$path" ]; then
      /sbin/insmod -s -f "$path" >/dev/null 2>&1 || error "Unable to load kernel module $module from $path"
      return 0
   fi

   local modulesPath=/usr/lib/vmware-tools/modules

   local rhel3="EL(|smp|hugemem)$"
   local rhel4="EL(|smp|hugemem)$"
   local rhel5="el5(|PAE)$"
   #RHEL 6 has unified the kernel, this regex does not really produce anything.
   #e.g. uname -r => 2.6.32-37.el6.x86_64
   local rhel6="el6([^.]*)"
   local sles9="(smp|default|bigsmp)$"
   local sles10="(smp|default|bigsmp|vmi|vmipae)$"
   local sles11="(default|pae|vmi)$"

   local dist=`get_dist_key` || error "Unable to detect distribution"
   eval "local regex=\$$dist"

   local kmodType=`echo $release | awk '{ match($0, /'$regex'/, arr)
                                          print arr[1] }'`

   # There is only one kernel type for UP and SMP systems on RHEL[56].
   if is_rhel && \
      [ `get_major_version` = "5" -o `get_major_version` = "6" ] && \
      [ -z $kmodType ]; then
      kmodType=smp
   fi

   local distroRelease=`get_release_type``get_release` || \
      error "Unable to determine distribution release version."

   # For RHEL systems only: ABI is guaranteed, so fall back on a default
   # path if one doesn't exist for this minor version.
   if is_rhel && [ ! -e "$modulesPath/$distroRelease" ]; then
      distroRelease=default
   fi

   # If there is no extension then it means it's UP.
   if [ -z $kmodType ]; then
      if ! is_rhel; then
         error "Unable to determine kernel type"
      elif uname -v | grep ' SMP ' >/dev/null 2>&1; then
         kmodType=smp
      else
         kmodType=up
      fi
   fi

   path=$modulesPath/$distroRelease/$kmodType/$module.$ext

   /sbin/insmod -s -f "$path" >/dev/null 2>&1 || error "Unable to load kernel module $module from $path"
   return 0
}

# Outputs the first path found to stdout and exits with 0, otherwise
# exits with non-zero exit code.
find_first_exists()
{
   for path in "$@"; do
      if [[ -e "$path" ]]; then
         echo "$path"
         exit 0
      fi
   done

   exit 1
}

# Executes sed-type replacements on the given file in-place.  All
# other arguments are passed to sed.
replace()
{
   local temp="`mktemp /tmp/vmwareReplace.XXXXXX`"
   local file="${@:$#}"          # Last argument
   local sedArgs="${@:1:$#-1}"   # Take arg 1 through last-1

   if sed "$sedArgs" < "$file" > "$temp"; then
      mv -f "$temp" "$file"
   fi

   rm -f "$temp"
}

# Strips all leading a trailing whitespace from stdin, writing to
# stdout.
strip()
{
   tr -d "[:space:]"
}

# Returns 0 if running RHEL, otherwise 1.
is_rhel()
{
   [ -e $REDHAT_RELEASE ]
}

# Returns 0 if running SLES, otherwise 1.
is_sles()
{
   [ -e $SUSE_RELEASE ]
}

# Returns 0 if running Ubuntu, otherwise 1.
is_ubuntu()
{
   [ -e $UBUNTU_RELEASE ]
}

# Get a given field from the SuSE release file.
get_sles_release_field()
{
   local field="$1"
   shift

   local val=`awk '{ match($0, /'$field' = ([0-9]+)$/, arr)
          print arr[1] }' < $SUSE_RELEASE`
   echo $val | strip
}

# Returns the SLES major version (8, 9, 10, etc.)
get_sles_major_version()
{
   get_sles_release_field VERSION
}

# Returns the RHEL major version (3, 4, 5, etc.)
get_rhel_major_version()
{
   sed 's/^.* [Rr]elease \([0-9]*\).*$/\1/' $REDHAT_RELEASE
}

# Returns the SP level on SLES
get_sles_release()
{
   local release=`get_sles_release_field PATCHLEVEL`

   # If we didn't find anything just assume GA.
   if [ -n "$release" -a "$release" != 0 ]; then
      echo $release
   fi
}

# Returns the update level on RHEL
get_rhel_release()
{
   # otherwise, fall back to /etc/redhat-release
   if [ `get_major_version` = "5" -o \
        `get_major_version` = "6" ]; then
      local regex="[0-9]+\.([0-9]+)"
   else
      # Only tested with RHEL4.
      local regex="Update ([0-9]+)\)$"
   fi

   release=`awk '{ match($0, /'"$regex"'/, arr)
                     print arr[1] }' < $REDHAT_RELEASE`

   # If we didn't find anything just assume GA.
   if [ -n $release ]; then
      echo $release
   fi
}

# Returns the full version of Ubuntu without the separating space
# (704, 710, 804, etc.)
get_ubuntu_major_version()
{
   # lsb_release is not a core part of an Ubuntu installation; but
   # /etc/lsb-release _is_ (part of the "base-files" package).
   ( . /etc/lsb-release; echo $DISTRIB_RELEASE | tr -d . )
}

get_major_version()
{
   get_`get_dist`_major_version
}

get_release()
{
   get_`get_dist`_release
}

# Return the prefix used for the release version number.
get_release_type()
{
   local release=`get_release`

   if [ -z $release ]; then
      echo ga
      exit
   fi

   if is_rhel; then
      echo u
   elif is_sles; then
      echo sp
   else
      echo
      exit 1
   fi
}

get_dist()
{
   if is_rhel; then
      echo rhel
   elif is_sles; then
      echo sles
   elif is_ubuntu; then
      echo ubuntu
   else
      echo unknown
      exit 1
   fi
}

# Get a unique key representing a combination of the distribution and
# its major version.
#
# Examples:
#    rhel4
#    sles9
#    ubuntu704
get_dist_key()
{
   local dist=`get_dist`
   echo $dist`get_${dist}_major_version`
}

# Is a given module loaded?
#
# XXX: This is copied from services.sh because there are functions in
# util.sh that call isLoaded so the function should live there but
# will require some refactoring.
isLoaded() {
  local module="$1"

  /sbin/lsmod | awk 'BEGIN {n = "no";} {if ($1 == "'"$module"'") n = "yes";} END {print n;}'
}
