#!/bin/ksh
# This scripts downloads the rpm.rte & dnf_bundle.tar
# rpm.rte-4.13.0.x which is a prequisite for dnf.
# dnf_bundle.tar contains dnf and its dependent packages.
# This script checks if any of the package from dnf_bundle is
# already installed and then installs the packages accordingly.

# Check if we are running this as the root user.
if [[ "$(id -u)" != "0" ]]
then
    echo "This script must be run as root."
    exit 1
fi

oslvl=`/usr/bin/oslevel`
if [[ "$oslvl" = "6.1.0.0" ]]
then
    echo "dnf and dependencies can be installed on AIX 7.1 and higher versions."
    exit 1
fi

prog=${0##*/}
yum4=0

usage() {
    print >&2 "Usage: $prog <-y> <-n> -?

      -n    Install DNF where both YUM and DNF can coexist if YUM is installed already.
	    If YUM is not installed, only DNF will be installed.
      -y    Update YUM3 to YUM4(softlink to DNF).
	    Use this option if want to redirect all YUM commands to DNF."

    exit 1
}

if [[ $# -ne 1 ]]
then
    usage
    exit 1
fi

arg=`echo $1 | /usr/bin/cut -c1-3`
if [[ "$arg" = "-n" ]]
then
    yum4=1
elif [[ "$arg" = "-y" ]]
then
    yum4=2
else
    usage
fi

# Check if /tmp has enough space to download rpm.rte & dnf_bundle
# and size for extracting rpm packages.
# 40 MB for rpm.rte and 367 MB for dnf_bundle.tar, 213 MB for
# rpm packages extracted.

typeset -i total_req=`echo "(1036)" | bc`
tmp_free=`df -m /tmp | sed -e /Filesystem/d | awk '{print $3}'`
if [[ $tmp_free -le $total_req ]]
then
    echo "Please make sure /tmp has around 1036MB of free space to download and"
    echo "extract files from dnf_bundle."
    exit 1
fi

# Check if /opt is having enough space to install the packages from dnf_bundle.
# Currently we need around 213MB of free space in /opt filesystem.
typeset -i total_opt=`echo "(850)" | bc`
opt_free=`df -m /opt | sed -e /Filesystem/d | awk '{print $3}'`
if [[ $opt_free -le $total_opt ]]
then
    echo "Total free space required for /opt filesystem to install rpms"
    echo "  from dnf_bundle is around 850MB."
    echo "Please increase the size of /opt and retry."
    exit 1
fi

# Create a temporary directroy where all downloads should go.
curr_time=`date +%Y%m%d%H%M%S`
mkdir -p /tmp/dnf-$curr_time
tmppath=`echo /tmp/dnf-$curr_time`
cp dnf_bundle_beta_v2.tar $tmppath
cd $tmppath

echo "\nExtracting dnf_bundle.tar ..."
tar -xvf dnf_bundle_beta_v2.tar

# Extract the os specific gcc packages.
if [ "$oslvl" = "7.2.0.0" ]
then
    echo "Extracting AIX 7.2 gcc tar"
    tar -xvf gcc_72.tar
elif [ "$oslvl" = "7.1.0.0" ]
then
    echo "Extracting AIX 7.1 gcc tar"
    tar -xvf gcc_71.tar
fi

# Update rpm.rte to latest version.
# From AIX 7.1 TL5 & 7.2 TL2 rpm.rte shipped is 4.13.0.1.
# Installation will be skipped if either 4.9.1.3 or 4.13.0.1 is installed. 
echo "Installing rpm.rte at the latest version ..."
echo "This may take several minutes depending on the number of rpms installed..."
installp -qacXYd rpm.rte all
if [[ $? -ne 0 ]]
then
    echo "rpm.rte update to latest version failed."
    cd - >/dev/null 2>&1
    rm -rf $tmppath
    exit 1
fi

# Check if some packages are already installed from the dnf_bundle.
echo "\n"
echo "Checking whether any of the rpms from dnf_bundle are already installed..."
echo "Takes couple of minutes to process.\n"

if [[ ! -e extra_list ]]
then
    echo "Missing extra_list file from the bundle"
    exit 1
fi

extra_pkgs=$(cat extra_list)
set -A rpms_list
set -A pkg_list
set -A pkgname_list
set -A pkg_name_ver_list
set -A install_list

if [[ $yum4 -eq 1 ]] # Install only dnf. Both yum & dnf can coexists.
then
    ls *.rpm | /usr/bin/egrep -v "yum" | while read rpm_file
    do
        pkg_list[${#pkg_list[*]}]=`/usr/opt/rpm/bin/rpm -qp --qf "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}" $rpm_file`
        pkgname_list[${#pkgname_list[*]}]=`/usr/opt/rpm/bin/rpm -qp --qf "%{NAME}" $rpm_file`
	rpms_list[${#rpms_list[*]}]=`echo $rpm_file`
	pkg_name_ver_list[${#pkg_name_ver_list[*]}]=`/usr/opt/rpm/bin/rpm -qp --qf "%{NAME}-%{VERSION}-%{RELEASE}" $rpm_file`
    done
elif [[ $yum4 -eq 2 ]] # Install yum4 which is a softlink to dnf.
then
    ls *.rpm | while read rpm_file
    do
        pkg_list[${#pkg_list[*]}]=`/usr/opt/rpm/bin/rpm -qp --qf "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}" $rpm_file`
        pkgname_list[${#pkgname_list[*]}]=`/usr/opt/rpm/bin/rpm -qp --qf "%{NAME}" $rpm_file`
	rpms_list[${#rpms_list[*]}]=`echo $rpm_file`
	pkg_name_ver_list[${#pkg_name_ver_list[*]}]=`/usr/opt/rpm/bin/rpm -qp --qf "%{NAME}-%{VERSION}-%{RELEASE}" $rpm_file`
    done
fi

# Compares the two packages version number
function cmp_version {
   large=$(echo  $1 $2 |
         awk '{ split($1, a, ".");
         split($2, b, ".");
         x = 0;
         for (i = 1; i <= 4; i++)
            if (a[i] < b[i]) {
                x = 3;
                break;
            } else if (a[i] > b[i]) {
                x = 2;
                break;
            }
           print x;
         }')
   return $large
}

# Compares the two packages release number
function cmp_release {
   arg1=`expr $1`
   arg2=`expr $2`
   if [[ $arg1 < $arg2 ]]
   then
      return 3
   elif [[ $arg1 > $arg2 ]]
   then
      return 2
   fi
}

let "pkg_count=0"
pkg_count=${#pkg_list[@]}
p=0
while (( $p < $pkg_count ))
do
    /usr/opt/rpm/bin/rpm -q --qf %{NAME} ${pkgname_list[$p]} > /dev/null 2>&1
    n_inst=$?
    if [[ $n_inst -eq 0 ]] # package with the same name is installed
    then
	inst_pkgname=`/usr/opt/rpm/bin/rpm -q --qf %{NAME} ${pkgname_list[$p]}` 
	/usr/opt/rpm/bin/rpm -q --qf %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH} ${pkg_list[$p]} > /dev/null 2>&1
	i_inst=$?
	if [[ $i_inst -ne  0 ]] # package with exact version isn't installed
	then
	    # check if rpm from dnf_bundle is higher version than the one installed.
	    inst_pkgname_ver=`/usr/opt/rpm/bin/rpm -q --qf %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH} ${pkgname_list[$p]}`
	    if [[ "${pkgname_list[$p]}" = "$inst_pkgname" ]]
	    then
		inst_ver=`/usr/opt/rpm/bin/rpm -q --qf %{VERSION} ${pkgname_list[$p]}`
		rpm_ver=`/usr/opt/rpm/bin/rpm -qp --qf %{VERSION} ${rpms_list[$p]}`
		cmp_version $inst_ver $rpm_ver
		rc1=$?
		if [[ $rc1 -eq 0 ]] # Same version matches. Check for the release.
		then
		    inst_rel=`/usr/opt/rpm/bin/rpm -q --qf %{RELEASE} ${pkgname_list[$p]}`
		    rpm_rel=`/usr/opt/rpm/bin/rpm -qp --qf %{RELEASE} ${rpms_list[$p]}`
		    cmp_release $inst_rel $rpm_rel 
		    rc2=$?
		    if [[ $rc2 -eq 3 ]] # Installed release is less than the bundle 
		    then
			echo "$inst_pkgname_ver will be updated to ${pkg_name_ver_list[$p]}" 
			install_list[${#install_list[*]}+1]=${rpms_list[$p]}
		    elif [[ $rc2 -eq 2 ]] # Higher version is already installed
		    then
		   	echo "Skipping ${pkg_name_ver_list[$p]} as higher version $inst_pkgname_ver is installed."
		    fi
		elif [[ $rc1 -eq 3 ]] # Installed rpm lower than the bundle
		then
		    echo "$inst_pkgname_ver will be updated to ${pkg_name_ver_list[$p]}"
		    install_list[${#install_list[*]}+1]=${rpms_list[$p]}
		elif [[ $rc1 -eq 2 ]]
		then
		    echo "Skipping ${pkg_name_ver_list[$p]} as higher version $inst_pkgname_ver is installed."
		fi
	    fi
	elif [[ $i_inst -eq 0 ]] # exact version of the package is installed. Do nothing.
	then
	    echo "${pkg_name_ver_list[$p]} is already installed" 
	fi
    elif [[ $n_inst -ne 0 ]] # package with the name isn't installed
    then
	    # Install only required packages, skip sub-packages install
	    echo $extra_pkgs | grep "${pkg_name_ver_list[$p]}" > /dev/null 2>&1
	    if [[ $? -ne 0 ]]
	    then
		echo "${pkg_name_ver_list[$p]} will be installed"
		install_list[${#install_list[*]}+1]=${rpms_list[$p]}
	    fi
    fi
    (( p+=1 ))
done 

if [[ ${#install_list[@]} -eq 0 ]]
then
    echo "\ndnf and all it's dependencies are already installed."
    cd - >/dev/null 2>&1
    rm -rf $tmppath
    exit 0
fi

echo "\nInstalling the packages...\n"
rpm -Uvh ${install_list[@]}

if [[ $? -eq 0 ]]
then
    cd - >/dev/null 2>&1
    rm -rf $tmppath
    echo
    echo "\033[1;32mdnf installed successfully. \033[m"
    echo "\033[1;33mPlease run 'dnf update' to update packages to the latest level. \033[m"
    echo
elif [[ $? -ne 0 ]]
then
    echo
    echo "\033[1;31mdnf installation failed. \033[m" 
    echo "If the failure was due to a space issue, increase the size of /opt and re-run dnf.sh"
    echo "or install the downloaded packages from $tmppath manually."
    echo "Another reason for failure could be mixing of Toolbox packages and packages from other sources."
    echo
fi
