#!/bin/sh
#
# Copyright 1998 VMware, Inc.  All rights reserved.
#

# Basic support for IRIX style chkconfig 
# chkconfig: 3 1 01
# description: Initializes various VMkernel modules.

# load system helper functions.
. /etc/init.d/functions
. /etc/init.d/vmware-functions

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

subsys=vmware

##XXX No longer valid when proc depricated
# Are VMs running?
vmware_in_use() {
  local nvms=`grep -s vmm /proc/vmware/sched/cpu 2>&1 | wc -l`

  if [ "$nvms" -gt "0" ]; then
    return 0
  else
    return 1
  fi
}

# Load drivers, and do other random crud
start_drivers() {
  start_vmkdump 

  #Make sure we have a system uuid
  /usr/sbin/esxcfg-advcfg -u > /dev/null 2>&1

  start_networking

  # Initialize migration configuration, this has to go after nicteaming module
  echo "migration migration" | do_module_file

  # Load upper-level storage drivers
  start_storage

  # Stop progress display on vmkernel status terminal
  /usr/sbin/esxcfg-advcfg -q -s 0 /Misc/BootProgress

  action "   Restoring Resource Groups" /usr/sbin/esxcfg-resgrp -r
}

# Start vmkdump services
start_vmkdump() {
   extract_vmkdump 
   action "   VMware dump partition" /usr/sbin/esxcfg-dumppart -S
}

# Extract the vmk core and log file if there is a new core dump
extract_vmkdump() {
  local devname=`/usr/sbin/esxcfg-dumppart --get-config | cut -f2`
  local curTime

  if [ -z "$devname" ]; then
    return 1
  fi

  curTime=`date "+%m%d%y.%H.%M"`
  zDumpName="$vmkdump_dir"/vmkernel-zdump-"$curTime"
  $vmkdump --zdumpname $zDumpName \
           --devname $devname   \
           --newonly >> /tmp/vmkdump.log 2>&1

  # log an error to the summary log if we find a core file
  if [ -e  "$zDumpName.1" ]; then
     summaryLog "VMkernel error"
  fi

  return $?
}

# Read a line at a time from standard input and load each module appropriately.
do_module_file() {
  while read ; do
    set -- $REPLY
    module=$1
    tag=$2

    basemod=`echo $module | sed "s/\.o$//"`
    if [ "$tag" != "cosShadow" ]; then
       if [ `$modloader -lb | grep -wc $basemod` -ne 0 ]; then
          action "   VMkernel module $module already loaded" /bin/true
          continue
       fi 
    fi

    shift 2
    action "   Loading VMkernel module $module" $modloader $vmkmod_dir/"$module" "$tag" "$@"
  done
}

# Unload storage drivers
stop_storage() {
   
    # Do a volume rescan to clear the volume object cache,
    # else we might not be able to unload FS drivers.
    vmkfstools -V

    # XXX: should we explicitly kill iscsi daemon and remove the module?

    #
    # Unload drivers in the following order:
    #    0. File system filter drivers
    #    1. Base file system drivers
    #    2. Logical volume managers
    #    3. FS device services
    #    4. FS device drivers
    #
    
    for vmfs_module in "deltadisk" "vmfs2" "vmfs3" "nfsclient" "lvmdriver"; do
       # Some of the drivers may not be loaded in the first place. 
       if [ `$modloader -lb | grep -wc $vmfs_module` -ne 0 ]; then
          $modloader -u $vmfs_module
       fi 
    done
}

# Stop the vmkernel drivers.
# (At least the ones that need to be stopped / quiesced)
stop_drivers() {
  if isVMkernelLoaded; then 
     # Unload storage modules from VMKernel
     stop_storage

     summaryLog "unloaded VMkernel"
  fi 
}

# Load upper level storage drivers
start_storage() {
  # Load lvm driver (before the file system drivers)
  echo "lvmdriver lvmdriver" | do_module_file
  # Load file system drivers
  echo "nfsclient nfsclient" | do_module_file
  echo "vmfs3 vmfs3" | do_module_file
  echo "deltadisk deltadisk" | do_module_file

  # Mount /vmfs.  vmfs drivers are either already loaded (vmfs3) or
  # loaded in the late-init script (vmfs2).
  mount -n -t vmfs /vmfs /vmfs

  # Initialize Queued-VMFS3 partitions. This must be done after
  # mounting /vmfs in order for automatic volume naming to work.
  vmfsqueuetool -F

  action "   Restoring SCSI Paths" /usr/sbin/esxcfg-mpath -r
}

#
# late vmkernel config.  
# Initialize things that must be done _after_ networking 
# has been enabled.
#
start_late_vmk_config() {
  # Depends on vmkernel id (which depends on networking)

  # vmfs2 walks again.  fear me.
  echo "vmfs2 vmfs2" | do_module_file

  # Pick a vmfs for cos coredumps.  Make a best effort attempt to 
  # find the one with the most free space.
  #
  local cosCoreFile=`/usr/sbin/esxcfg-advcfg -q -g /Misc/CosCorefile`
  if ! echo $cosCoreFile | grep -q /vmfs/volumes ; then
     cosCoreFile=""
  elif [ ! -d `dirname $cosCoreFile` ]; then
     cosCoreFile=""
  else
     local vmfsVersion=`vmkfstools -P \`dirname $cosCoreFile\` | head -1 | grep VMFS`
     if [ -z "$vmfsVersion" ]; then
        cosCoreFile=""
     elif ( echo $vmfsVersion | grep -q 'VMFS-2' ); then
        cosCoreFile=""
     fi
  fi

  if [ -z $cosCoreFile ] ; then
     # vmfs 2 is mounted read-only, so only pick vmfs3 volumes
     local coreVolume=""
     for vmfs in `vdf -P /vmfs/volumes 2>&1 | grep vmfs | sort -nk4 | awk '{print $1}'`; do
        if [ -z "$coreVolume" ]; then
           if vmkfstools -P $vmfs | grep -q "VMFS-3"; then
              coreVolume=$vmfs
           fi
        fi
     done
 
     if [ -n "$coreVolume" ]; then
        local host=`hostname -s`
        /usr/sbin/esxcfg-advcfg -q -s $coreVolume/cos-core-$host /Misc/CosCorefile
     fi
  fi

  #
  # Networking causes the default sysctl options to be loaded from sysctl.conf
  #

  if [ $buildType != "release" ] ; then
     echo 1 2> /dev/null > /proc/sys/kernel/sysrq
     /usr/lib/vmware/bin/vsi_traverse -s > /dev/null
  fi 
}

#
start_networking() {

   echo "etherswitch etherswitch" | do_module_file
   echo "shaper shaper" | do_module_file

   if ! isStateless; then
      # restore pnic speed/duplex settings
      action "   Restoring Nic Settings" /usr/sbin/esxcfg-nics -r

      #restore virtual switches
      action "   Restoring Virtual Switches" /usr/sbin/esxcfg-vswitch -r

      echo "tcpip tcpip" |do_module_file

      action "   Restoring VMkernel Networking" /usr/sbin/esxcfg-vmknic -r
      action "   Setting VMkernel gateway" /usr/sbin/esxcfg-route -r

      # Must be loaded before vmxnet_console.
      echo "tcpip cosShadow -m cosShadow cosShadow=1" |do_module_file
   else 
      # Set up console networking. 
      action "   Creating Virtual Interfaces" /usr/sbin/esxcfg-vswif -A
   fi

   #restore console networking
   action "   Restoring Virtual Interfaces" /usr/sbin/esxcfg-vswif -r

}

setup_linuxnet() {
   action "Setting up Service Console networking" /usr/sbin/esxcfg-linuxnet --setup
}

remove_linuxnet() {
   /usr/sbin/esxcfg-linuxnet --remove > /dev/null
}

# Bottom-half of hardware change work in ramdisk.
namegen=/var/log/initrdlogs/namegen
namereboot=/var/log/initrdlogs/namereboot
check_hw_config() {
   rm $namegen >& /dev/null && action "Hardware reconfiguration" esxcfg-boot --name-devices && esxcfg-init -n
   rm $namereboot >& /dev/null && action "Rebooting for hardware reconfig to take effect" true && reboot 
}

#
# Check to see if we're doing the first boot after an upgrade,
# and perform necessary post-boot upgrade tasks.  At this time
# that means upgrading multipathing config and cleaning up
# old config files.
#
# Note that vmfs2 must be loaded in order to get the required
# information, so this must be called after the late vmkernel config.
#
check_for_upgrade() {
   if [ -f /etc/vmware/hwconfig ]; then
      action "   Upgrading SCSI Path config" esxcfg-upgrade -o
      action "   Loading upgraded SCSI Paths" /usr/sbin/esxcfg-mpath -r
   fi
}

#
# log a message to the summary log
#
summaryLog() {
   TIME=`date +"%s"`
   logger -p "local6.info" "($TIME)" $1
}

writeMotd() {
   local who=$1; shift
   local msg=$*
   touch /etc/motd 
   cp -f /etc/motd /etc/vmware/motd.$who
   echo -e "\nALERT [$(date)]:\n$msg\n" > /etc/motd
}

restoreMotd() {
   local who=$1; 
   if [ -f /etc/vmware/motd.$who ]; then
      mv /etc/vmware/motd.$who /etc/motd
   fi
}

csok=/etc/vmware/csok
csfail=/etc/vmware/csfail
saveConfig() {
   restoreMotd "ecb" 
   if isStateless; then
      touch $csok
   else 
      action "Saving $productName configuration" "/usr/sbin/esxcfg-boot -r >& /dev/null"
      if [ $? -eq 0 ]; then
         touch $csok
      else 
         touch $csfail
      fi
   fi
}

configMotd() {

   if [ -e $csok ]; then
      rm -f $csok
   else 
      if [ -e $csfail ]; then
         # esxcfg-boot -r failed.
         rm -f $csfail
         local err="Configuration changes were not saved successfully during previous shutdown."
         local act="Please file a problem report including output of vm-support."
         local msg="$err\n$act"
         writeMotd "ecb" $msg
      else
         # Unclean shutdown; if refresh/rebuild required, reboot. 
         if [ `/usr/sbin/esxcfg-boot -k` = "yes" ]; then
            echo "Rebooting to apply changes made during previous session"   
            sync 
            reboot
         fi
      fi
   fi
}

#run all first run stuff with and without upgrade
check_first_run() {
   #is this a first run?
   if isFirstRun ; then
      touch $csok  
      #is this an upgrade?
      if [ -e $vmware_etc_dir/hwconfig ]; then
         #its an upgrade
         /bin/true
      else
         #its a fresh install
         /sbin/chkconfig netfs off > /dev/null 2>&1
         /sbin/chkconfig nfslock off > /dev/null 2>&1
         /sbin/chkconfig audit off > /dev/null 2>&1
         /sbin/chkconfig portmap off > /dev/null 2>&1
         # our firewall script does what is necessary
         /sbin/chkconfig iptables off
	 # remove checking password validation for root
	 /usr/bin/chage -M -1 root > /dev/null 2>&1
      fi

      setFirstRun
   fi
}

main() {

# See how we were called.
case "$1" in
   start)
        # 'runlevel' is defined when the caller is rc.
        if [ -z $runlevel ]; then
           echo "This service cannot be started manually."
           exit 1
        fi

        [ -d /var/lock/subsys ] || mkdir -p /var/lock/subsys
        touch /var/lock/subsys/$subsys

        #Temporary workaround for bug 127517
        for l in libcrypto.so.0.9.7 libssl.so.0.9.7; do
           if [ ! -e /usr/lib/vmware/lib/$l ]; then
	       ln -s /lib/$l /usr/lib/vmware/lib/$l
           fi
        done
	#Temporary workaround for PR 137174
        for l in libz.so.1; do
           if [ ! -e /usr/lib/vmware/lib/$l ]; then
	       ln -s /usr/lib/$l /usr/lib/vmware/lib/$l
           fi
        done

        check_first_run

	#check for required configfile upgrades
	esxcfg-configcheck

  	# Clean the slate. 
  	remove_linuxnet
        restoreMotd "tsm"
        restoreMotd "ecb"

        configMotd
        if isTSMode; then
           writeMotd "tsm" "This $productName machine is currently booted into troubleshooting mode."
           setup_linuxnet
           action "Skipping $productName services." /bin/true
           exit 0
        fi

        echo "Starting $productName services:"

        check_hw_config
        start_drivers

        summaryLog "loaded VMkernel"

        #disable kudzu for vmkernel.
        /sbin/chkconfig kudzu off

        #Work around for bug 62830 (you still don't want to know).
        perl -e 'use IO::Socket; $0 = 'portResv902'; my $sock = new IO::Socket::INET(LocalPort => "902", Proto => "tcp", Listen => 1, Reuse => 1); die "Could not create socket: $!\n" unless $sock; sleep (1) while(1);' &
        ;;

   stop)
        # 'runlevel' is defined when the caller is rc.
        if [ -z $runlevel ]; then
           echo "This service cannot be stopped manually."
           exit 1
        fi

        # From vmkernel statusterm to COS vt. 
        chvt 1

        if ! isTSMode; then
            echo "Stopping $productName services:"
            scripts=`ls $shutdowndir | grep -e '^[0-9]\+\.' | sort -n`
            for f in $scripts; do
               echo "   Calling $f" && $shutdowndir/$f
            done
            stop_drivers
        fi

        isTSMode && restoreMotd "tsm" 
        saveConfig
        
        rm -f /var/lock/subsys/$subsys
	;;

   status)
        if isVMnixmodLoaded; then
           echo 'The vmnixmod kernel module is loaded.'
        fi
        if isVMkernelLoaded; then 
           echo 'The VMkernel is loaded.'
        fi
	if vmware_in_use; then
           echo 'At least one virtual machine is still running.'
	fi
	;;

   late-vmk-config)
       start_late_vmk_config
       check_for_upgrade
       ;;
   *)
	echo "Usage: `basename "$0"` {start|stop|status}"
	exit 1
esac

exit 0
}

main $*
