# -*-Shell-script-*-
# Steven Shiau <steven@nchc.org.tw>
# License: GPL
#
# functions	This file contains functions to be used by most or all
#		shell scripts in the DRBL environment
#
# cut the functions from drblsrv-rh, drblsrv-mdk, drbl.pl
# /opt/drbl/sbin/drbl-functions
# drbl-client-root-passwd 
# a lot of functions in drbl-login-switch ?
# mknic-nbi create_depmod_env modify
# resize_part check_input_hd()

# set the locale...
export LC_ALL=C

# Source DRBL setting
. /opt/drbl/conf/drbl.conf

check_distribution_name() {
 #8.0:/etc/issue or /etc/redhat-release: Red Hat Linux release 8.0 (Psyche)
 #9.0:/etc/issue or /etc/redhat-release: Red Hat Linux release 9 (Shrike)
 #FC1:/etc/fedora-release: Fedora Core release 1 (Yarrow)
 #FC2:/etc/fedora-release: Fedora Core release 2 (Tettnang)
 #MDK 9.2: /etc/mandrake-release: "Mandrake Linux release 9.2 (FiveStar) for i586" 
 #MDK 10.0 (Community): /etc/mandrake-release: "Mandrake Linux release 10.0 (Community) for i586" 
 #MDK 10.0 (Official): /etc/mandrake-release: "Mandrake Linux release 10.0 (Official) for i586" 
 #$OS_Version will be the index for rc.sysinit in drblsrv-rh, drblsrv-mdk and drblpush
  grep -q "Red Hat Linux release 8.0 (Psyche)" /etc/redhat-release 2>/dev/null && OS_Version="RH8.0"
  grep -q "Red Hat Linux release 9 (Shrike)" /etc/redhat-release 2>/dev/null && OS_Version="RH9"
  grep -q "Fedora Core release 1 (Yarrow)" /etc/fedora-release 2>/dev/null && OS_Version="RHFC1"
  grep -q "Fedora Core release 2 (Tettnang)" /etc/fedora-release 2>/dev/null && OS_Version="RHFC2"
  grep -q "Mandrake Linux release 9.2 (FiveStar) for i586" /etc/mandrake-release 2>/dev/null && OS_Version="MDK9.2"
  grep -q "Mandrake Linux release 10.0 (Community) for i586" /etc/mandrake-release 2> /dev/null && OS_Version="MDK10.0"
  grep -q "Mandrake Linux release 10.0 (Official) for i586" /etc/mandrake-release 2> /dev/null && OS_Version="MDK10.0"
  echo $OS_Version
}

#
apt_install_result_msg() {
  RETVAL="$1"
  if [ "$RETVAL" -gt 0 ]; then 
    echo "$msg_failed_to_install_pkgs"
    echo "$msg_please $msg_browse $drbl_url_zh_TW $msg_or $drbl_url_en_US $msg_for_more_details. "
    echo "$msg_press_ctrl_c_stop"
    read
    exit 1 
  fi
}

# create the shared library program runtime env.
create_depmod_env() {
  local newroot="$1"
  [ -z $newroot ] && exit 1
  cp --parents /sbin/depmod $newroot
  if ldd /sbin/depmod > /dev/null 2>&1; then
    depmod_lib_need=$(ldd /sbin/depmod | cut -d" " -f3)
    cp --parents $depmod_lib_need $newroot
  fi
}
clean_depmod_env() {
  local newroot="$1"
  [ -z $newroot ] && exit 1
  [ -f $newroot/sbin/depmod ] && rm -f $newroot/sbin/depmod
  if ldd /sbin/depmod > /dev/null 2>&1; then
    depmod_lib_need=$(ldd /sbin/depmod | cut -d" " -f3)
    for f2rm in `echo $depmod_lib_need`; do
      [ -f $newroot/$f2rm ] && rm -f $newroot/$f2rm
    done
  fi
}

# function to create chkconfig environment
create_chkconfig_env() {
  local newroot="$1"
  [ -z $newroot ] && exit 1
  chkconfig_lib_need=$(ldd /sbin/chkconfig | cut -d" " -f3)
  cp --parents $chkconfig_lib_need $newroot
  cp --parents /sbin/chkconfig $newroot
}

# function to clean chkconfig environment
clean_chkconfig_env() {
  local newroot="$1"
  [ -z $newroot ] && exit 1
  chkconfig_lib_need=$(ldd /sbin/chkconfig | cut -d" " -f3)
  [ -f $newroot/sbin/chkconfig ] && rm -f $newroot/sbin/chkconfig
  for f2rm in `echo $chkconfig_lib_need`; do
    [ -f $newroot/$f2rm ] && rm -f $newroot/$f2rm
  done
}

# Check if root or not
check_if_root() {
   if [ ! "$UID" = "0" ]; then
     echo
     echo "[$LOGNAME] You need to run this script \"`basename $0`\" as root."
     echo
     exit 1
   fi
}

# force to run apt-get install, this will force to install the necessary packages
check_apt_integrity() {
   apt-get -f --yes install
}

# function to get the autologin_account
# input is the host dir, like /tftpboot/nodes/192.168.1.1, then
# return the auto_login ID
get_autologin_account() {
    local ihost="$1"
    # $auto_login_id and $echo_no_digit_0_1 are global variables
    # auto login username is set as hostname
    . $ihost/etc/sysconfig/network
    auto_login_id="$HOSTNAME"
    if grep -q $auto_login_id /etc/passwd ; then
      # account $auto_login_id exists, show it
      echo "$auto_login_id"
    fi
}

# check switch if it is input correct as on or off
check_switch_on_off() {
  local switch="$1"
  case "$switch" in
    on|ON|[oO]|[nN]|off|OFF|[oO][fF][fF])
         break
         ;;
     "")
         usage && exit 1
         ;;
     *)
         echo "You must specify \"on\" or \"off\" !!! Program stop!!!"
         exit 1
         ;;
  esac
}

#
create_passwd_env() {
  local newroot="$1"
  [ -z $newroot ] && exit 1
  passwd_lib_need=$(ldd /usr/bin/passwd | cut -d" " -f3)
  cp --parents $passwd_lib_need $newroot
  cp --parents /usr/bin/passwd $newroot

  # /bin/echo is necessary for passwd --stdin
  cp --parents /bin/echo $newroot

  cp --parents -r $PAM_need_files $newroot
  # we need sh to run the script, borrow it from mkinitrd-net's busybox
  cp /usr/lib/mkinitrd-net/initrd-skel/bin/sh $newroot/bin
}

clean_passwd_env() {
  local newroot="$1"
  [ -z "$newroot" ] && exit 1
#  passwd_lib_need=$(ldd /usr/bin/passwd | cut -d" " -f3)
#  [ -f "$newroot/usr/bin/passwd" ] && rm -f $newroot/usr/bin/passwd
#  [ -f "$newroot/bin/echo" ] && rm -f $newroot/bin/echo
#  for f2rm in $passwd_lib_need; do
#    [ -f $newroot/$f2rm ] && rm -f $newroot/$f2rm
#  done
#  for f2rm in $PAM_need_files; do
#    [ -f $newroot/$f2rm ] && rm -f $newroot/$f2rm
#  done
#  [ -f "$newroot/bin/sh" ] && rm -f $newroot/bin/sh
  for d2rm in bin  lib  usr; do
    if [ -d "$newroot/$d2rm" ]; then
      [ -n "$verbose" ] && echo "Cleaning the unnecessary directory $newroot/$d2rm ..."
      rm -rf $newroot/$d2rm
    fi
  done
}

# check if the user input /dev/hda, /dev/hdb...
check_input_hd() {
    local target_hd="$1"
    case "$target_hd" in
	 [hs]d[a-z])
	   continue
	   ;;
	 *)
	  echo "Unknown HD device! Program stop!"
          Usage
	  exit 1
    esac
}

## description:
##   convert devfs names into normal short ones, written by Tom Rini.
fixdevfs() {
    ## get partition number, if any
    local PARTNUM="${1##*[a-z]}"
    ## Find the bus type.
    local TYPE="$(v=${1#/dev/} ; echo ${v%/host*})"
    ## Find the host number.
    local HOST="$(v=${1#/dev/*/host} ; echo ${v%/bus*})"
    ## Find the bus number.
    local BUS="$(v=${1#/dev/*/bus} ; echo ${v%/tar*})"
    ## Find the target.
    local TARGET="$(v=${1#/dev/*/target} ; echo ${v%/lun*})"

    case "$TYPE" in
	ide)
	case "$HOST" in
	    0)
	    case "$TARGET" in
		0)
		local DEV=hda
		;;
		1)
		local DEV=hdb
		;;
	    esac
	    ;;
	    1)
	    case "$TARGET" in
		0)
	        local DEV=hdc
	        ;;
		1)
		local DEV=hdd
		;;
	    esac
	    ;;
	    *)
		echo "${1#/dev/}"
		#echo "Unable to translate this device, try again without devfs."
		return 1
	esac
	local DEV="${DEV}${PARTNUM}"
	echo "$DEV"
	return 0
	;;
	scsi)
	local LUN="$(v=${1#/dev/*/lun} ; echo ${v%/*})"

	## In this case, we need to figure out what number our device is
	local DEVCOUNT=0

	## copy scsi file into a variable removing "Attached Devices"
	## which is the first line. this avoids a lot of
	## [incmopatible] crap later, and improves readability.

	## find number of lines once and recycle that number, to save
	## some time (linecount is a bit slow). subtract one line
	## to scrap Attached Devices:

	local SCSILINES="$(($(wc -l /proc/scsi/scsi | cut -d' ' -f1) - 1))"
	local PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"

	for i in $(seq $(($SCSILINES / 3))) ; do

	    ## put every scsi device into one single line
	    local DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
	    [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVINFO=$DEVINFO"

	    ## cut the type field, expect "Direct-Access" later.
	    local DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
	    [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVTYPE=$DEVTYPE"

	    if [ "$DEVTYPE" = "Direct-Access" ] ; then
		## Lets find out some more information
		## get the device id.
		local DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVID=$DEVID"

		## get the device lun.
		local DEVLUN="$(v=$(echo ${DEVINFO##*Lun: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVLUN=$DEVLUN"

		## get the device channel.
		local DEVCHAN="$(v=$(echo ${DEVINFO##*Channel: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCHAN=$DEVCHAN"

		## get the scsi host id.
		local DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVHOST=$DEVHOST"

		local DEVCOUNT="$(($DEVCOUNT + 1))"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCOUNT=$DEVCOUNT"
		if [ "$DEVHOST" = "$HOST" -a "$DEVCHAN" = "$BUS" -a \
		    "$DEVID" = "$TARGET" -a "$DEVLUN" = "$LUN" ] ; then
		    local DEV="sd$(smalltr $DEVCOUNT)${PARTNUM}"
		    echo "$DEV"
		    return 0
		fi
	    fi
	done
	echo "${1#/dev/}"
	#echo "Unable to translate this device, try again without devfs."
	return 1
	;;
	*)
	echo "${1#/dev/}"
	#echo "Unknown bus"
	return 1
	;;
    esac
    ## we should never get here
    return 1
}

conv_devfspart_to_tradpart() {
   # function to convert devfs partitions to traditional partitions
   # fix the disk/partition, we do not want the devfs style for clonezilla
   TARGET_FILE="$1"
   [ -z "$TARGET_FILE" ] && echo "No output filename! Program stop!!!" && return 1
   [ -f "$TARGET_FILE" ] && rm -f $TARGET_FILE
   while read major minor block p x; do
     p="$(fixdevfs "/dev/$p")"
     echo "$major $minor $block $p" >> $TARGET_FILE
   done < /proc/partitions
}

# get dhcpd interface
get_dhcpd_interface() {
  local INTERFACES= INTERFACES_TMP=
  # get the setting of dhcp server
  . /etc/sysconfig/dhcpd
  # collect those interface, filter out other options, such as -p 60
  INTERFACES=""
  for ieth in $DHCPDARGS; do
     INTERFACES_TMP="$(echo $ieth |grep -o eth.*)"
     INTERFACES="$INTERFACES $INTERFACES_TMP"
  done
  echo $INTERFACES
}

# HD dma status
check_hd_dma() {
   local hd_dev=$1
   DMA_status=`/sbin/hdparm -d $hd_dev |grep using_dma |awk  '{print $3}'`
   echo "$DMA_status"
}

# turn on hd dma
turn_on_hd_dma() {
    local hd_dev="$1"
    if [ -n "$hd_dev" ]; then
      /sbin/hdparm -d1m1c1 $hd_dev
      DMA=`check_hd_dma $hd_dev`
      if [ -n "$DMA" ]; then
         # This is IDE device, we can get DMA status
         [ "$DMA" -eq 0 ] && echo "Warning!!! Failed to turn on harddisk \"$hd_dev\" DMA... The clone performance might be NOT good..." && sleep 5
      else
         # This is SCSI device, we can not get DMA status
         echo "No HD DMA information, maybe this not a IDE device!"
      fi
    else
         echo "To turn on HD dma, you have to specify the HD dev!"
    fi
}

# do not let screen be blank
screen_not_blank() {
    /usr/bin/setterm -blank 0
}

# set passwd login for single user mode
set_clients_rc1_passwd() {
  local rc1_sulogin="~~:S:wait:/sbin/sulogin"
  for ihost in $drblroot/*; do
    if ! grep -q ^$rc1_sulogin $ihost/etc/inittab ; then
      echo "Set the single user password for client `basename $ihost`, this will be safer..."
      cat <<-EOF >> $ihost/etc/inittab

# Single User Mode Password
$rc1_sulogin
EOF
    fi
  done
}

# function to active the /proc/partitions. For SCSI devices, even when device
# modules is loaded, the device is not shown in /proc/partitions if no program
# like fdisk or sg_map runs... We also do it for /dev/hdx.
active_proc_partitions() {
   for ihd in /dev/[hs]d[a-z]; do
      fdisk -l $ihd &> /dev/null
   done
}

# function : stop_ocs
stop_ocs_if_necessary() {
  if [ -f "$ocsroot/ocsmgrd.lock" ]; then
    echo "Your system is already in clonezilla mode... we will stop it first, then change to other mode..."
    $DRBL_SCRIPT_PATH/sbin/drbl-ocs stop
  fi
}
