#!/bin/bash
# sapconf - Configure SAP requirements on your Linux system
#
# This script is built with a lot of support by SAP LinuxLab <linux@sap.com>
#
# Authors:
# Markus Koch <mkoch@redhat.com>
# Sherry Yu <syu@redhat.com>
# Frank Danapfel <fdanapfe@redhat.com>
# Jaroslav Škarvada <jskarvad@redhat.com>
# Nils Philippsen <nils@redhat.com>
# Jan Grulich <jgrulich@redhat.com>
# Than Ngo <than@redhat.com>

############################################################################
#
# Script to prepare RHEL7 according to SAP Note 2002167
#
#---------------------------------------------------------------------------
#
# requires: tuned-profiles-sap
#
# options:
#   -d <dbtyp>   : used to set special parameters for Sybase and Oracle, respectively (i.e. sybase|syb|oracle|ora)
#   -f           : FORCE mode: do actions which are not required, but makes your life easier (i.e. disable firewall)
#   -n           : CHECK_ONLY mode: no modification will be made to the system
#   -q           : quiet execution. log file directory: /var/log/sap
#   -h           : help message
#
# returncodes:
#       0 : all works well
#       1 : non-critical or user break
#       4 : exit to critical error in script
#
#############################################################################

####################################
#
# GLOBAL Variables
#

SAPCONF_PACKAGE=`rpm -q sapconf`

export SCRIPTNAME=sapconf
export SAPCONF_MAJOR_VERSION=$(echo $SAPCONF_PACKAGE | cut -d'-' -f2 | cut -d'.' -f1)
export SAPCONF_MINOR_VERSION=$(echo $SAPCONF_PACKAGE | cut -d'-' -f2 | cut -d'.' -f2)
export SAPCONF_BUILD_VERSION=$(echo $SAPCONF_PACKAGE | cut -d'-' -f3 | cut -d'.' -f1)
export LOGDIR=/var/log/sap
export LOGFILE=${LOGDIR}/${SCRIPTNAME}-$(date +"%Y%m%d%H%M").log

####################################
#
# LOCAL Variables
#

SAP_NOTE_RHEL7="SAP Note 2002167"
CHECK_ONLY=0
FORCE_MODE=0
QUIET=0
EXIT_STATE=1

# rec_count counts the number of lines of variable array REC[] that contains recommendations to be put at the end of the $LOGFILE
rec_count=0

TUNED_SAP_PROFILE=sap-netweaver

#####################################
#
# Important parameters
# for RHEL7 according to SAP Note 2002167
#

# List of variables with according _MIN values, for boundschecking
VARS='TMPFS_SIZE SHMALL SHMMAX SEMMSL SEMMNS SEMOPM SEMMNI MAX_MAP_COUNT'

# minimal size of TMPFS is 8 GB (2 GB 32-Bit)
TMPFS_SIZE_MIN=8 # 8 GB (SAP Note 941735)
TMPFS_SIZE_MIN_32=2

SHMALL_MIN=5242880 # 20 GB (SAP Note 941735)
SHMALL_MIN_32=2097152 # 8 GB

SHMMAX_MIN=21474836480 # 20 GB (SAP Note 941735)
SHMMAX_MIN_32=2313682943 # 2,3 GB (SAP Note 941735)

SEMMSL_MIN=1250
SEMMNS_MIN=256000
SEMOPM_MIN=100
SEMMNI_MIN=8192

MAX_MAP_COUNT_MIN=2000000

SAPGROUPLIST="sapsys sdba dba"

## Define additional kernel parameters for Sybase
SYB_VARS=""
SYB_EXTRA_KERNEL="RANDOMIZE_VA_SPACE EXEC_SHIELD"
RANDOMIZE_VA_SPACE_REQ=0
EXEC_SHIELD_REQ=0

# Define required RPMs
# RPMS contains rpms recommended by SAP Note
RPMS="@compat-libraries @large-systems @network-file-system-client @performance uuidd tuned-profiles-sap"
# VIRTRPMS is a variable used by function virtrpms and check_rpms. In virtrpms the rpms that are required by SAP on virtual guests will be set in VIRTRPMS, and installed by check_rpms.  Currently vm-dump-metrics is installed on KVM/RHEV based guests. XEN and VMware are not implemented.
VIRTRPMS=""

## Define
EXTRA_RPMS=""
# Use this line for oracle 11R2
ORA_EXTRA_RPMS="@development libaio libaio-devel compat-libstdc++-33 elfutils-libelf-devel libgcc libstdc++ unixODBC unixODBC-devel mksh"


#####################################
# function: usage
# parameters: -
#
# called on wrong usage
#
# return codes:
#    0, parameter -h
#    1, wrong usage
function usage() {
cat << EOU
Usage: $0 [-d <dbtype>] [-f] [-n] [-q]

   -d <dbtyp>   : used to set special parameters for Sybase and Oracle, respectively (i.e. sybase|syb|oracle|ora)
   -f           : FORCE mode: do actions which are not required, but makes your life easier (i.e. disable firewall)
   -n           : CHECK_ONLY mode: no modification will be made to the system
   -q           : quiet execution. log file directory: /var/log/sap
   -h           : help message

EOU
exit $EXIT_STATE
}

#####################################
# function: out
# parameters: "output", string
#             "status", Boolean (0=fail, 1=OK)
#
# called for output, logs output to $LOGFILE
#
function out() {
if [ $QUIET -eq 0 ]; then
  echo  "$@"
fi

[ ! -d ${LOGDIR} ] && mkdir -p ${LOGDIR}
echo "$@" >> ${LOGFILE}

## Optional: logger -p local3.info -t SAP "$@"

}

#####################################
# function: error
# parameters: "output", string
#             "exitcode", int
#
# writes textmessage to stderr & Logfile
# and exits if exitcode > 0
#
function error() {
echo "$1" >&2

[ ! -d ${LOGDIR} ] && mkdir -p ${LOGDIR}
echo "ERROR $1" >> ${LOGFILE}
## Optional: logger -p local3.err -t SAP "$1"

[ ${2:-0} -ne 0 ] && exit $2
}

#####################################
# function: rec
# parameters: "recommendations", string
#
# Variable array for Recommended settings
#
function rec() {
rec_count=`expr $rec_count + 1`
REC[$rec_count]="$1"
}

#####################################
# function: rec_out
# parameters: "output", string
#             "status", Boolean (0=fail, 1=OK)
#
# called for logs output to $LOGFILE at the end of the execution
#
function rec_out() {
out ""
out "######         RECOMMENDATIONS                ######"
out "##  Below are recommended settings that can not   ##"
out "##  Be carried out by the ${SCRIPTNAME} script          ##"
out "##  Please check and set them manually            ##"
out "## ---------------------------------------------- ##"
for (( i=1; i<=$rec_count; i++))
do
out ""
out "$i: ${REC[$i]}"
done
out "######       END OF RECOMMENDATIONS           ######"
}



#####################################
# function: virtrpms
# parameters: -
#
# checks if the system runs on a virtual machine or hypervisor
# returns: packages for KVM
#          packages for RHEV Hypervisor
#          packages for Xen    **** UNTESTED ****
#          packages for VMware **** UNTESTED ****
#          nothing for everything else
#
function virtrpms() {
        case $(dmidecode -s system-product-name) in

        KVM)
                VIRTRPMS="vm-dump-metrics";
                out "System is virtualized on KVM. vm-dump-metrics rpm is required and will be installed during execution"
                ;;

        RHEV*)
                rec "System is virtualized on RHEV Hypervisor. Please check SAP Note 1400911 — Linux: SAP on Red Hat KVM - Kernel-based Virtual Machine for information on setting up the SAP Host monitoring on RHEV"
                ;;

        HVM.domU)        ### not Checked ###
                rec "System is virtualized on XEN. Please check according SAP Notes for additional settings"
                ;;

        VMware*)
                rec "System is VMware Virtual Platform. Please check according SAP Notes for additional settings"
                ;;

        *)
                out "System is not recognized as a virtual guest. It's either on bare metal or on a Hypervisor that's not supported"
                ;;

esac

}


####################################
# function: check_env
# parameters: none
#
# called to check the kernel parameters
#
function check_env() {

# TMPFS_SIZE
grep '/dev/shm' /proc/mounts &>/dev/null
if [ $? -eq 0 ]; then # TMPFS already mounted, check size and correct it if necessary
        TMPFS_SIZE=`df -k /dev/shm | tail -n 1 | awk '{print $2}'`
        # rounding to full Gigabytes
        TMPFS_SIZE=$(( ( $TMPFS_SIZE + 1048576 ) / 1048576 ))
else # TMPFS not mounted
        TMPFS_SIZE=0
fi
SHMMAX=`/sbin/sysctl -n kernel.shmmax`

SEMMSL=`awk '{print $1}' /proc/sys/kernel/sem`
SEMMNS=`awk '{print $2}' /proc/sys/kernel/sem`
SEMOPM=`awk '{print $3}' /proc/sys/kernel/sem`
SEMMNI=`awk '{print $4}' /proc/sys/kernel/sem`

SHMALL=`/sbin/sysctl -n kernel.shmall`
MAX_MAP_COUNT=`/sbin/sysctl -n vm.max_map_count`

MAIN_MEMORY_TOTAL=`awk '/MemTotal:/ {print $2}' /proc/meminfo`
SWAP_SPACE_TOTAL=`awk '/SwapTotal:/ {print $2}' /proc/meminfo`
VIRT_MEMORY_TOTAL=$(( ${MAIN_MEMORY_TOTAL} + ${SWAP_SPACE_TOTAL} ))
# rounding to full Gigabytes
VIRT_MEMORY_TOTAL=$(( ( ${VIRT_MEMORY_TOTAL} + 1048576 ) / 1048576 ))

# Required size of TMPFS: (RAM + SWAP) * 0,75 (SAP Note 941735)
TMPFS_SIZE_REQ=$(( $VIRT_MEMORY_TOTAL * 75 / 100 ))

# kernel.shmall is in 4 KB pages; minimum 20 GB (SAP Note 941735)
SHMALL_REQ=$(( $VIRT_MEMORY_TOTAL * 1024 * 1024 / 4 ))
# kernel.shmmax is in Bytes; minimum 20 GB (SAP Note 941735)
SHMMAX_REQ=$(( $VIRT_MEMORY_TOTAL * 1024 * 1024 * 1024 ))

# The two kernel parameters required by Sybase ASE
RANDOMIZE_VA_SPACE=`/sbin/sysctl -n kernel.randomize_va_space`
EXEC_SHIELD=`/sbin/sysctl -en kernel.exec-shield`

# Check if exec-shield is not set as it seems to be not used on 64bit systems, otherwise set it
# to 0 to indicate that is already disabled
if [ -z "$EXEC_SHIELD" ]; then
    EXEC_SHIELD=0
fi

ARCH=`uname -m`
case $ARCH in
        i?86) # 32-bit OS, use 32-bit limits if existent
                for i in $VARS; do
                        min=${i}_MIN
                        min32=${i}_MIN_32
                        [ -n "${!min32}" ] && eval $min=${!min32}
                done
        ;;
esac

# Set all _REQ values to their recommended size
for i in $VARS; do
        min=${i}_MIN
        req=${i}_REQ; [ -z ${!req} ] && eval $req=0
        #[ $VERBOSE -eq 1 ] && echo "OLD: $i: ${!i} ($req=${!req}) ($min=${!min})"
        [ ${!req} -lt ${!min} ] && eval $req=${!min} # new = max(calculated, minimum)
        # 'unlimited' is realized as -1, take care of this
        if (( $(bc <<< "${!i} < 0") )); then
                eval $req=$((${!i}))
        else
                (( $(bc <<< "${!i} > ${!req}") )) && eval $req=${!i} # new = max(current, recommended)
        fi
        #[ $VERBOSE -eq 1 ] && echo "NEW: $i: ${!i} ($req=${!req}) ($min=${!min})"
done

out "Checking Kernel Parameters ... In Progress"
# Print Server environment
ec=0
for v in $VARS; do
   eval "s=\$${v} ; r=\$${v}_REQ"
   if (( $(bc <<< "$s == $r") )) ; then
        out "$v : $s  ... OK"
   else
        out "$v : set: $s, required: $r ... NEEDS TO BE CHANGED"
        if [ $CHECK_ONLY == 1 ]; then
               rec "Kernel Parameter $v : set: $s, required: $r ... NEEDS TO BE CHANGED"
        fi
        ec=$(( $ec + 1 ))
   fi
done

for v in $SYB_VARS; do
   eval "s=\$${v} ; r=\$${v}_REQ"
   if [ $s -eq $r ]; then
        out "$v : $s  ... OK"
   else
        out "$v : set: $s, required by Syabse ASE: $r ... NEEDS TO BE CHANGED"
        if [ $CHECK_ONLY == 1 ]; then
               rec "Kernel Parameter $v : set: $s, required by Sybase ASE: $r ... NEEDS TO BE CHANGED"
        fi
        ec=$(( $ec + 1 ))
   fi
done


if [ $ec -eq 0 ]; then
        out "Kernel parameters are ready for SAP"
else
        if [ $CHECK_ONLY == 0 ]; then
                out "Updating Kernel Parameters"
                #### Update TMPFS SIZE ####
                if [ $TMPFS_SIZE -lt $TMPFS_SIZE_REQ ]; then
                        out "TMPFS SIZE $TMPFS_SIZE smaller than required size $TMPFS_SIZE_REQ ... SETTING REQUIRED VALUE"
                        # Check /etc/fstab for /dev/shm entries (TMPFS set correctly)
                        if [ $TMPFS_SIZE -eq 0 ]; then # TMPFS not mounted
                                update_fstab $TMPFS_SIZE_REQ
                                mount /dev/shm || error 'Something went wrong in changing the /etc/fstab for TMPFS.' 0
                        else # TMPFS mounted, check size and correct it if necessary
                                update_fstab $TMPFS_SIZE_REQ
                                mount -o remount /dev/shm || error 'Something went wrong in changing the /etc/fstab for TMPFS.' 0
                        fi
                        out "TMPFS SIZE Set to $TMPFS_SIZE_REQ ... DONE"
                fi

                out "Activating tuned '$TUNED_SAP_PROFILE' profile"
                tuned-adm profile $TUNED_SAP_PROFILE || error "Unable to activate tuned '$TUNED_SAP_PROFILE' profile."  3
        fi # [ $CHECK_ONLY == 0 ]
fi #[ $ec -eq 0 ]
}

#####################################
# function: update_limits_conf
# parameters: domain, string
#             type, string
#             item, string
#             value, int
#
# example: update_limits_conf @sapsys hard nofile 32800
#
# sets process limits
function update_limits_conf() {
        local date olds oldval news newval LIMITS
        LIMITS=/etc/security/limits.d/99-sap-limits.conf
        LIMITS_SAP_CONF=/etc/security/limits.d/99-sap.conf
        LIMITS_CONF=/etc/security/limits.conf
        date=`date -u +"%Y-%m-%d %H:%M:%S %Z"`
        newval=($1 $2 $3 $4)
        news=${newval[*]}

        olds=`tac "$LIMITS_CONF" | grep -E "^[^#]*$1" | grep "$2" | grep -m1 "$3"`
        if [ $? -eq 0 ]; then # entry there, update
                oldval=($olds);
                if [ "${oldval[3]}" != "${newval[3]}" ]; then
                        sed -i "s/$olds/# Changed by sapconf on $date\n#\ &\n$news/" "$LIMITS_CONF"
                fi
        elif [ -e "$LIMITS_SAP_CONF" ] ; then
                olds=`tac "$LIMITS_SAP_CONF" | grep -E "^[^#]*$1" | grep "$2" | grep -m1 "$3"`
                if [ $? -eq 0 ] ; then # entry there, update
                        oldval=($olds)
                        if [ "${oldval[3]}" != "${newval[3]}" ]; then
                                 sed -i "s/$olds/# Changed by sapconf on $date\n#\ &\n$news/" "$LIMITS_SAP_CONF"
                        fi
                fi

        else
                if [ -e "$LIMITS" ]; then
                        olds=`tac "$LIMITS" | grep -E "^[^#]*$1" | grep "$2" | grep -m1 "$3"`
                        if [ $? -eq 0 ]; then # entry there, update
                                oldval=($olds);
                                if [ "${oldval[3]}" != "${newval[3]}" ]; then
                                        sed -i "s/$olds/# Changed by sapconf on $date\n#\ &\n$news/" "$LIMITS"
                                fi
                        else # no entry, make one
                                echo -e "# Added by sapconf on $date\n$news" >> "$LIMITS"
                        fi
                else
                        echo -e "# Added by sapconf on $date\n$news" >> "$LIMITS"
                fi
        fi
}


#####################################
# function: update_fstab
# parameters:
#
# called to update /etc/fstab with the correct values for tmpfs
#

function update_fstab() {
        # We expect TMPFS_SIZE (in GB) as parameter
        local date olds oopt nopt news size_given i
        date=`date -u +"%Y-%m-%d %H:%M:%S %Z"`
        olds=`grep -m1 -E '^[^#].*/dev/shm' /etc/fstab`
        if [ $? -eq 0 ]; then # entry there, update
                old=($olds)
                oopt=(${old[3]//,/ }); unset nopt
                for i in ${oopt[*]}; do
                        if [ ${i:0:5} == 'size=' ]; then
                                size_given=1
                                i="size=$1g"
                        fi
                        nopt="$nopt,$i"
                done
                nopt=${nopt#,}
                [ -z "$size_given" ] && nopt="$nopt,size=$1g"
                news="${olds/${old[3]}/$nopt}"
                if [ "$olds" == "$news" ]; then
                        error "W: The correct /dev/shm values are already in /etc/fstab but not active. Remount /dev/shm!" 0
                else
                        sed -i "s@$olds@# Changed by ${SCRIPTNAME} on $date\n#&\n$news@" /etc/fstab
                fi
        else # no entry, make one
                # 2009-09-16 d022127: SLES11.0 can't cope with /dev/shm entries (BZ 516769)
                [ "$OS_VERSION" = "11.0" ] || \
                echo -e "# Added by ${SCRIPTNAME} on $date\ntmpfs\t/dev/shm\ttmpfs\tsize=$1g\t0 0" \
                        >> /etc/fstab
        fi
}

#####################################
# function: check_fqdn
# parameters: none
#
# checks if the hostname of the RHEL system is set correctly, i.e.
# shortname in /etc/sysconfig/network
# no hostname in the localhost definitions of  /etc/hosts
# the hostnames in /etc/hosts need to be <ip> <FQDN> <shortname>

function check_fqdn() {

# Check if hostname and dns-setup is set correctly (take from satellite-script)
h=$(hostname)
hs=$(hostname -s)
hl=$(hostname -f)
dn=$(dnsdomainname)

### now try to detect hostname from domain entry /etc/resov.conf
[ -z "${dn}" ] &&\
        dn=$(awk ' ( $1 == "domain" ) { print $2 }' /etc/resolv.conf) &&\
        hl=${hs}.${dn}

### now try to detect hostname from search entry /etc/resov.conf
[ -z "${dn}" ] &&\
        dn=$(awk ' ( $1 == "search" ) { print $2 }' /etc/resolv.conf) &&\
        hl=${hs}.${dn} &&\
        rec "Domain set to \"$dn\" from /etc/resolv.conf. Please check if this is correct"

### now try to detect hostname from DNS
if [ -z "${dn}" ]; then
        ### This fails, if ip of $hs is unreachable or $hs unknown in nameservice
        ip=$(ping -q -c 1 -t 1 $hs | grep PING | sed -e "s/^[^(]*[(]//" | sed -e "s/[)].*$//")
        [ "${ip}" == "127.0.0.1" ] &&\
                ip=$(ip addr show dev $( netstat -r | awk ' ( $1 == "default" ) { print $NF }')|awk '( $1 == "inet" ) { print $2 } ' | cut -d/ -f1)
        if [ -n "${ip}" ]; then
                dn=$(/usr/bin/host $ip  | cut -d' ' -f 5 | cut -d. -f 2-)
                dn=$(echo ${dn%.})
                hl=${hs}.${dn}
        fi
fi

### No still no domainname is found DNS is not configured correctly
### TODO: put recommendation and continue to run
if [ -z  "${dn}" ]; then
        out "ERROR: DNS is not configured correctly. Please fix and rerun script."
        exit 4
fi

### 


##### At this time hl, hs and dn are set correctly ####
##### In case $h = $hl => sysconfig network wrong #####

if [ "${hs}.${dn}" != "${hl}" -o "${hs}" != ${h} ]; then
    out "hostname settings are wrong ... not OK"
    if [ $CHECK_ONLY == 0 ]; then
     ## shortname in /etc/sysconfig/network
        fh=$(awk -F= '( $1 == "HOSTNAME" ) {print $2}' /etc/sysconfig/network)
        fhs=$(awk -F= '( $1 == "HOSTNAME" ) {print $2}' /etc/sysconfig/network | cut -d. -f1)
        timestamp=$(date +"%Y%m%d%H%M")
        [ "${h}" != "${hs}" ] &&\
                mv /etc/sysconfig/network /etc/sysconfig/network.${SCRIPTNAME}-$timestamp &&\
                sed -e "s/^HOSTNAME=.*/HOSTNAME=$hs/g" /etc/sysconfig/network.${SCRIPTNAME}-$timestamp > /etc/sysconfig/network  &&\
                hostname ${hs}

     out "/etc/sysconfig/network has been updated. The original file is backed up at /etc/sysconfig/network.${SCRIPTNAME}-$timestamp"
     else
        rec "/etc/sysconfig/network settings are not correct. Please set the correct hostname settings according to $SAP_NOTE_RHEL7"
     fi
else
    out "/etc/sysconfig/network settings ... OK"
fi

## modify /etc/hosts
## at this point in time /etc/sysconfig/network is ok.
## so still need to check, if hosts is correct.
# Check what happens if $hs=localhost or if a different branch needs to be added, which
#               finds the ip adress of the first network card
#               ask DNS for the name and configures accordingly

# check localhost settings
# remove hostnames from localhost IPs
# insert a line with correct IPs

### hl, dn, hs have the correct values that schould be set.
### hostname should return the correct value, so re-reading it

h=$(hostname)
hl=$h.$dn

### This fails, if ip of $hs is unreachable or $hs unknown in nameservice
ip=$(ping -q -c 1 -t 1 $hs | grep PING | sed -e "s/^[^(]*[(]//" | sed -e "s/[)].*$//")

## Now $h must be equal to $hs, if not something went wrong or the script is run in check mode
### TODO: put recommendation and continue to run
[ "${h}" != "${hs}" ] &&\
         out "ERROR: Your network setup is broken. Please fix your network setup according to $SAP_NOTE_RHEL7 and rerun this script" &&\
         exit  4

## Now check if localhost settings need to be corrected
fix_localhost=0
lhl=$(grep localhost /etc/hosts)
if [ -n "${lhl}" ]; then
        echo "$lhl" | grep ${hs} > /dev/null 2>&1 && fix_localhost=1;
else
    out "warn: no localhost setting /etc/hosts"
    fix_localhost=1
fi

### Check if $ip is only once in /etc/hosts
num_ip=$( grep "^${ip}" /etc/hosts | wc -l)

### Now if localhost is ok  and names are resolved correctly, assume /etc/host is ok. ####
if [ "$(hostname -f)" == "${hl}" ] && [ $fix_localhost -eq 0 ] && [ $num_ip -eq 1 ]; then
         out "/etc/hosts ... OK"
else
         out "/etc/hosts checking ... not OK"

         ####  if ip is localhost, get ip from primary interface, identified by the default route
         [ "${ip}" == "127.0.0.1" ] &&\
                ip=$(ip addr show dev $( netstat -r | awk ' ( $1 == "default" ) { print $NF }')|awk '( $1 == "inet" ) { print $2 } ' | cut -d/ -f1)

         if [ $CHECK_ONLY == 0 ]; then
                timestamp=$(date +"%Y%m%d%H%M")
                hosts_temp=$(/bin/mktemp /etc/hosts.sap.XXXXXX)

                awk -v HS=$hs -v HL=$hl -v IP=$ip '
                        BEGIN { hns=0;
                                print ("127.0.0.1       localhost.localdomain   localhost" )
                              }
                        { if  ( $1 == "127.0.0.1" )   { # do nothing
                                                        l=1
                                                      }
                        else if ( $1 == "::1" )       { # print correct IPv6 localhost if in hosts
                                                          print ("::1        localhost6.localdomain6   localhost6" )
                                                      }
                        else if (( $1 == IP ) && ( hns == 0 )) {
                                        if (($2 == HL) && ($3 == HS))  { print $0
                                                                         hns=1 }
                                        else { printf( $1" "HL" "HS);
                                               for (i=2; i < NF; i++) { if (( $i !=  HL ) && ( $i != HS )) printf ( " "$i ) }
                                               print ""
                                               hns=1
                                        }
                              }
                        else if ( $1 != IP ) { print $0 }
                        }
                        END { # if hns=0 no hostname entry has been in hosts
                                if ( hns == 0 ) print (IP" "HL" "HS)
                }        ' /etc/hosts > "$hosts_temp"

                 cp /etc/hosts /etc/hosts.${SCRIPTNAME}-$timestamp
                 chmod --reference=/etc/hosts "$hosts_temp"
                 if selinuxenabled; then
                     chcon --reference=/etc/hosts "$hosts_temp"
                 fi
                 mv "$hosts_temp" /etc/hosts
                 out "/etc/hosts has been updated. The original file is backed up at /etc/hosts.${SCRIPTNAME}-$timestamp"
         else
                 rec "/etc/hosts settings are not correct. Please set the correct hostname settings according to $SAP_NOTE_RHEL7"
         fi
fi
rm -f "$hosts_temp"

###### Just checking for length of hostname due to http://scn.sap.com/message/210257 /  SAP Note 611361 #####

[ $(hostname -s | wc -c) -gt 14 ] &&\
        rec "your hostname is greater than 13 characters. Please see SAP Note 611361 for details"
#[ $(hostname -s | wc -c) -gt 9 ] &&\
#        rec "your hostname is greater than 8 characters, which is not support on SAP rel. up to 4.5. Please see SAP Note 611361 for details"

}

#####################################
# function: check_security
# parameters: none
#
# for SAP SELinux needs to be set to permissive and
# the firewall needs to be disabled
# This is checked and implemented in this function

function check_security() {
# SELinux needs to be permissive or disabled
SELINUX_CONFIG=/etc/selinux/config
if egrep -q "^SELINUX=['\"]?enforcing" $SELINUX_CONFIG; then
        if [ $FORCE_MODE == 1 ]; then
                sed -i "s/^SELINUX=['\"]\?enforcing/SELINUX=permissive/" $SELINUX_CONFIG
                out "Configuring SELinux to be permissive..."
        else
                rec "SELinux is configured to be booted in enforcing mode. It's recommended to set to permissive. Please check $SAP_NOTE_RHEL7 for details."
        fi
else
    if egrep -q "^SELINUX=['\"]?disabled" $SELINUX_CONFIG; then
        rec "SElinux is configured to be disabled on boot. It's recommended to be set to permissive, however your system may then require to be relabeled. Please check $SAP_NOTE_RHEL7 for details."
    else
        if egrep -q "^SELINUX=['\"]?permissive" $SELINUX_CONFIG; then
            out "SELinux is configured to be permissive... OK"
        else
            rec "Unable to determine SELinux configuration ($SELINUX_CONFIG). Please configure your system to be booted with SELinux enabled in permissive mode. Please check $SAP_NOTE_RHEL7 for details."
        fi
    fi
fi

if [ $(getenforce | awk '{ print $1 } ') = enforcing ]; then
        rec "SELinux is running in enforcing mode. It's recommended to be set to permissive. Please check $SAP_NOTE_RHEL7 for details."
fi

# Firewall needs to be off
if systemctl status firewalld.service > /dev/null 2>&1 ; then
   if [ $FORCE_MODE == 1 ]; then
      # disable firewall or open required ports
      systemctl disable firewalld.service > /dev/null 2>&1
      systemctl stop firewalld.service > /dev/null 2>&1
      out "Firewall has been disabled for SAP"
   else
      rec "Firewall is enabled. If you leave the firewall on please open up the ports for SAP products. Firewall will be disabled by ${SCRIPTNAME} in execution mode"
   #out "Firewall state ... OK"
   fi
fi

}

#####################################
# function: check_chronyd
# parameters: none
#
# Enbale and Start ntpd service

function check_chronyd() {

systemctl status chronyd.service > /dev/null 2>&1
rc=$?
systemctl status ntpd.service > /dev/null 2>&1
rc1=$?
if [ $rc -eq 0 -o $rc1 -eq 0 ]; then
        out "NTP service is running ... OK"
else
        rec "NTP Service should be configured and started"
fi
}

#####################################
# function: check_rhn
# parameters: none
#
# Checks if system is subscribed to RHEL for SAP Channel

function check_rhn() {
if yum repolist | egrep "rhel-$(awk '{split($(NF-1), a, "."); print a[1]}' /etc/redhat-release)-for-$(uname -m)-sap-netweaver(-beta|-e4s|-eus)?-rpms" ; then
        out "RHEL system subscribed to RHEL for SAP channel ... OK"
else
        out "RHEL system not subscribed to RHEL for SAP channel ... WARNING"
        rec "RHEL system not subscribed to RHEL for SAP channel"
        rec "Red Hat recommends to get RHEL for SAP Business Applications subscriptions for all RHEL servers running SAP applications. See SAP Note 1631106"
fi
}

#####################################
# function: check_rpms
# parameters: none
#
# The required packages list is defined in RPMS, so that
# in can be changed according to SAPnote if the requirements change
# without changing the script

function check_rpms() {
#virtrpms checks if the system is a virtualization guest that requires additional rpms

# bz#1377766, dmidecode is not supported on s390x/ppc64, skip it on these
# platforms temporary before we have generic solution.
if [ -x /usr/sbin/dmidecode -o -x /usr/bin/dmidecode ] ; then
  virtrpms
fi

if [ $CHECK_ONLY == 0 ]; then
  for gp in $RPMS $EXTRA_RPMS $VIRTRPMS; do
        if [ "$(echo $gp | cut -c 1)" == "@" ]; then
                # rpm groups
                gi=0
                for r in $(repoquery --plugin -g --grouppkgs=mandatory -l $(echo $gp| cut -c2-)); do
                        rpm -q $r > /dev/null 2>&1
                        rc=$?
                        gi=$(( $rc + $gi ))
                done
                if [ $gi -gt 0 ]; then
                        out "Installing Group $gp ... "

                        #[ $CHECK_ONLY == 0 ] && yum -q -y install $gp
                        yum -q -y install $gp
                        out "Group $gp ... Installed"
                else
                        out "Group $gp ... Already Installed"
                fi
        else
                rpm -q $gp > /dev/null 2>&1
                rc=$?
                if [ $rc -eq 1 ]; then
                        out "Installing Package $gp ..."
                        #[ $CHECK_ONLY == 0 ] && yum -q -y install $gp
                        yum -q -y install $gp
                        out "Package $gp ... Installed"
                else
                        out "Package $gp ... Already Installed"
                fi
        fi
  done
else
  rec "The following packages or package groups are recommended. Missing ones will be installed during execution. Please make sure that your system is registered in Red Hat Network (RHN) to be able to retrieve software and update: $RPMS $EXTRA_RPMS $VIRTRPMS"
fi
}

#####################################
# function: check_links
# parameters: none
#
# It checks if same legacy links are made which are required for LDAP
# and older C++ libraries

function check_links() {
# set symbolic links for LDAP
if [ -L /usr/lib64/libldap.so.199 -a -L /usr/lib64/liblber.so.199 ]; then
        out "SAP LDAP Links ... OK"
else
        #out "SAP LDAP Links ... not OK"
        if  [ $CHECK_ONLY == 0 ]; then
                ( cd /usr/lib64;
                  ln -s libldap-2.3.so.0 libldap.so.199
                  ln -s liblber-2.3.so.0 liblber.so.199 )
                out "SAP LDAP Links ... Installed:"
                out "   /usr/lib64/libldap.so.199 -> libldap-2.3.so.0"
                out "   /usr/lib64/liblber.so.199 -> liblber-2.3.so.0"
        else
                rec "When using SAP software in an LDAP environment you need to install a symbolic link for two libraries. /usr/lib64/libldap.so.199 -> libldap-2.3.so.0, /usr/lib64/liblber.so.199 -> liblber-2.3.so.0. Please check the $SAP_NOTE_RHEL7 for details."
        fi
fi

# old version backward compatibility
if [ -L /usr/lib/libstdc++-libc6.1-1.so.3 ]; then
        out "SAP old version compat links ... OK"
else
        #out "SAP old version compat Links ... not OK"
        if  [ $CHECK_ONLY == 0 ]; then
            (cd /usr/lib; ln -s libstdc++-libc6.2-2.so.3 libstdc++-libc6.1-1.so.3)
            out "SAP old version compat links ... Installed"
            out "   /usr/lib/libstdc++-libc6.1-1.so.3 -> libstdc++-libc6.2-2.so.3"
        else
            rec "When using R3SETUP to install older product relreases, a symbolic link for backward compatibility is needed: /usr/lib/libstdc++-libc6.1-1.so.3 -> libstdc++-libc6.2-2.so.3. Plese check the $SAP_NOTE_RHEL7 for details."
        fi
fi
}

#####################################
# function: check_uuidd
# parameters: none
#
# checks if UUIDD is installed and running
# When CHECK_ONLY == 0, assume that UUIDD is already installed by check_rpms

function check_uuidd() {
if [ $CHECK_ONLY == 0 ]; then
        systemctl is-enabled uuidd.service > /dev/null 2>&1
        rc=$?
        if [ $rc -eq 0 ]; then
                out "Service uuidd autostart ... OK"
        else
                # uuidd permissions
                systemctl enable uuidd.service
                out "Service uuidd set to autostart ... OK"
        fi
        systemctl status uuidd.service > /dev/null 2>&1
        rc=$?
        if [ $rc -eq 0 ]; then
                out "Service uuidd already running"
        else
                out "Service uuidd not running ... Starting"
                systemctl start uuidd.service > /dev/null 2>&1
        fi
else
        rpm -q uuidd > /dev/null 2>&1
        rc=$?
        if [ $rc -eq 1 ]; then
                rec "Please make sure that package uuidd is installed, and service uuidd is started and set to autostart: yum install -y -q uuidd; service uuidd start; chkconfig uuidd on"
        else
                systemctl is-enabled uuidd.service > /dev/null 2>&1
                rc=$?
                if [ $rc -ne 0 ]; then
                        rec "Please make sure that service uuidd is set to autostart: systemctl enable uuidd.service"
                fi
                systemctl status uuidd.service > /dev/null 2>&1
                rc=$?
                if [ $rc -ne 0 ]; then
                        rec "Please make sure that service uuidd is started: systemctl start uuidd.service"
                fi
        fi
fi
}

#####################################
# function: check_glibc
# parameters: none
#
# checks if the minimum version of glibc is installed
function check_glibc() {
for GLIBC_PACKAGE in $(rpm -q glibc)
do
        REQUIRED_MAJOR_VERSION=2
        REQUIRED_MINOR_VERSION=17
        REQUIRED_BUILD_VERSION=73
        REQUIRED_BUILD_MINOR_VERSION=0
        ARCHITECTURE=$(echo $GLIBC_PACKAGE | rev | cut -d'.' -f1 | rev)
        MAJOR_VERSION=$(echo $GLIBC_PACKAGE | cut -d'-' -f2 | cut -d'.' -f1)
        MINOR_VERSION=$(echo $GLIBC_PACKAGE | cut -d'-' -f2 | cut -d'.' -f2)
        BUILD_VERSION=$(echo $GLIBC_PACKAGE | cut -d'-' -f3 | cut -d'.' -f1)
        BUILD_MINOR_VERSION=$(echo $GLIBC_PACKAGE | rev | cut -d'.' -f2- | rev | cut -s -d'_' -f2 | cut -d'.' -f2)
        UPDATE=0

        if [ -z $BUILD_MINOR_VERSION ]; then
              BUILD_MINOR_VERSION=0
        fi

        if [ $MAJOR_VERSION -lt $REQUIRED_MAJOR_VERSION ]; then
                UPDATE=1
        elif [ $MAJOR_VERSION -eq $REQUIRED_MAJOR_VERSION ]; then
                if [ $MINOR_VERSION -lt $REQUIRED_MINOR_VERSION ]; then
                        UPDATE=1
                elif [ $MINOR_VERSION -eq $REQUIRED_MINOR_VERSION ]; then
                        if [ $BUILD_VERSION -lt $REQUIRED_BUILD_VERSION ]; then
                                UPDATE=1
                        elif [ $BUILD_VERSION -eq $REQUIRED_BUILD_VERSION ]; then
                                if [ $BUILD_MINOR_VERSION -lt $REQUIRED_BUILD_MINOR_VERSION ]; then
                                        UPDATE=1
                                else
                                        UPDATE=0
                                fi
                        fi
                fi
        fi

        if [ $UPDATE -eq 1 ]; then
                if [ $CHECK_ONLY == 0 ]; then
                        out "Updating glibc ..."
                        yum -q -y update "glibc*.$ARCHITECTURE"
                else
                        if [ $REQUIRED_BUILD_MINOR_VERSION -eq 0 ]; then
                                rec "Newer version of glibc is required. Minimum required glibc.$ARCHITECTURE version is glibc-$REQUIRED_MAJOR_VERSION.$REQUIRED_MINOR_VERSION-$REQUIRED_BUILD_VERSION.el7.$ARCHITECTURE."
                                rec "Installed version is glibc-$MAJOR_VERSION.$MINOR_VERSION-$BUILD_VERSION.el7.$ARCHITECTURE."
                        else
                                if [ $BUILD_MINOR_VERSION -eq 0 ]; then
                                       rec "Newer version of glibc is required. Minimum required glibc.$ARCHITECTURE version is glibc-$REQUIRED_MAJOR_VERSION.$REQUIRED_MINOR_VERSION-$REQUIRED_BUILD_VERSION.el7_0.$REQUIRED_BUILD_MINOR_VERSION.$ARCHITECTURE. Installed version is glibc-$MAJOR_VERSION.$MINOR_VERSION-$BUILD_VERSION.el7.$ARCHITECTURE."
                                else
                                       rec "Newer version of glibc is required. Minimum required glibc.$ARCHITECTURE version is glibc-$REQUIRED_MAJOR_VERSION.$REQUIRED_MINOR_VERSION-$REQUIRED_BUILD_VERSION.el7_0.$REQUIRED_BUILD_MINOR_VERSION.$ARCHITECTURE. Installed version is glibc-$MAJOR_VERSION.$MINOR_VERSION-$BUILD_VERSION.el7_0.$BUILD_MINOR_VERSION.$ARCHITECTURE."
                                fi
                        fi
                fi
        else
                out "Required glibc.$ARCHITECTURE version is already installed"
        fi
done
}

####################################################################################
#
#  MAIN
#
####################################################################################

while getopts "c:d:fhnq" opt; do
  case $opt in
    c)
      SAPCONFIG=$OPTARG
      [ ! -r $SAPCONFIG ] && error "File $SAPCONFIG does not exist" 2
      . $SAPCONFIG
      ;;
    d)
      dbtyp=$OPTARG
        ;;
    f)
      FORCE_MODE=1
      ;;
    h)
      EXIT_STATE=0
      usage
      ;;
    n)
      CHECK_ONLY=1
      ;;
    q)
      QUIET=1
      ;;
    *)
      usage
      ;;
  esac
done

# Dispaly usage if there is unexpected parameter
shift $(( OPTIND -1 ))
if [ $1 ]; then
     usage
fi

out "######        ${SCRIPTNAME}-${SAPCONF_MAJOR_VERSION}.${SAPCONF_MINOR_VERSION}-${SAPCONF_BUILD_VERSION}  by Red Hat       ######"
if [ $CHECK_ONLY == 0 ]; then
        out "###### Preparing System for SAP Installation  ######"
else
        out "###### Checking System for SAP Installation    ######"
fi
out ""

# Check database specific settings
if [ -n "$dbtyp" ]; then
    case $dbtyp in
         sybase|syb)
                #Extra kernel parameters for Sybase ASE will be checked and set
                SYB_VARS="$SYB_EXTRA_KERNEL"
                ;;
        oracle|ora)
                #Extra packages for Oracle DB will be checked and installed
                EXTRA_RPMS="$ORA_EXTRA_RPMS"
                ;;
        db2|ada)
                ;;
        *)
                out "######   $dbtyp is not a valid db type, ignored  ######"
                ;;
    esac
fi

check_rhn
check_fqdn
check_security
# disable check_rpms as workaround on rhel 8 according to #1672323
if ( ! grep "release 8" /etc/redhat-release ) ; then
	check_rpms
	check_links
fi
check_uuidd
check_chronyd
check_env
for g in $SAPGROUPLIST; do
  update_limits_conf @$g hard nofile 32800
  update_limits_conf @$g soft nofile 32800
done
check_glibc

out ""
if [ $CHECK_ONLY == 0 ]; then
        out "###### System Updated. See RECOMMENDATIONS    ######"
else
        out "###### System Checked. See RECOMMENDATIONS    ######"
fi
rec_out

# end
