#!/bin/bash
################################################################################
#                             UpgradeFedora.sh                                 #
#                                                                              #
# This BASH script is used to upgrade from one version of Fedora to another.   #
# It uses the dnf command to bring very old versions of Fedora up to one of    #
# current releases.                                                            #
#                                                                              #
#                                                                              #
#                                                                              #
#                                                                              #
#                               Changelog                                      #
#   Date      Who      Description                                             #
#-----------  -------- --------------------------------------------------------#
# 2016/03/29  dboth    Initial code.                                           #
# 2016/12/10  dboth    Add input option for update release target version and  #
#                      added more sanity checking. Added test mode.            #
# 2017/05/21  dboth    Fixed Help.                                             #
# 2018/02/15  dboth    Added --refresh option to download.                     #
# 2020/02/15  dboth    Minor change to installing all updates prior to doing   #
#                      the upgrade itself.                                     #
# 2022/11/15  dboth    Change method for obtaining Fedora name to be more      #
#                      explicit and stable.                                    #
# 2023/04/18  dboth    Added new parameters to the dnf upgrade line.           #
#                                                                              #
#                                                                              #
#                                                                              #
#                                                                              #
#                                                                              #
#                                                                              #
#                                                                              #
################################################################################
################################################################################
#                                                                              #
#  Copyright (C) 2007, 2022 David Both                                         #
#  Millennium Technology Consulting LLC                                        #
#  http://www.millennium-technology.com                                        #
#                                                                              #
#  This program is free software; you can redistribute it and/or modify        #
#  it under the terms of the GNU General Public License as published by        #
#  the Free Software Foundation; either version 2 of the License, or           #
#  (at your option) any later version.                                         #
#                                                                              #
#  This program is distributed in the hope that it will be useful,             #
#  but WITHOUT ANY WARRANTY; without even the implied warranty of              #
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
#  GNU General Public License for more details.                                #
#                                                                              #
#  You should have received a copy of the GNU General Public License           #
#  along with this program; if not, write to the Free Software                 #
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   #
#                                                                              #
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
# Functions MUST go here                                                       #
################################################################################
################################################################################

################################################################################
# Help                                                                         #
################################################################################
Help()
{
   # Display Help
   echo "################################################################################"
   echo "#                           UpgradeFedora.sh                                   #"
   echo "################################################################################"
   echo "This program upgrades from older versions of Fedora to a specified later one."
   echo
   echo "Fedora $MinFedoraRelease is the earliest release supported for upgrades."
   echo
   echo "Syntax: ./UpgradeFedora.sh -h|V|g|tv[r Newreleasenumber]" 
   echo
   echo "g     Print the GPL license notification."
   echo "h     Print this help."
   echo "r     New release of Fedora to upgrade to. You must enter a valid release."
   echo "t     Test mode. Describes what it will do but makes no changes."
   echo "v     Verbose mode."
   echo "V     Print software version and exit."
   echo "################################################################################"
}

################################################################################
# Print the GPL license header                                                 #
################################################################################
gpl()
{
   echo
   echo "################################################################################"
   echo "#  Copyright (C) 2007, 2022  David Both                                        #"
   echo "#  Millennium Technology Consulting LLC                                        #"
   echo "#  http://www.millennium-technology.com                                        #"
   echo "#                                                                              #"
   echo "#  This program is free software; you can redistribute it and/or modify        #"
   echo "#  it under the terms of the GNU General Public License as published by        #"
   echo "#  the Free Software Foundation; either version 2 of the License, or           #"
   echo "#  (at your option) any later version.                                         #"
   echo "#                                                                              #"
   echo "#  This program is distributed in the hope that it will be useful,             #"
   echo "#  but WITHOUT ANY WARRANTY; without even the implied warranty of              #"
   echo "#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #"
   echo "#  GNU General Public License for more details.                                #"
   echo "#                                                                              #"
   echo "#  You should have received a copy of the GNU General Public License           #"
   echo "#  along with this program; if not, write to the Free Software                 #"
   echo "#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   #"
   echo "################################################################################"
   echo
}

################################################################################
# Quit nicely with messages as appropriate                                     #
################################################################################
Quit()
{
   if [ $error != 0 ]
   then 
      echo "Program terminated with error ID $error"
      rc=1
   else
      if [ $verbose = 1 ]
      then
         echo "Program terminated normally"
         rc=0
      fi
   fi

   exit $rc
}

################################################################################
# Gets simple (Y)es (N)o (Q)uit response from user. Loops until                #
# one of those responses is detected.                                          #
################################################################################
ynq()
{
   # loop until we get a good answer and break out
   while [ $OK = 0 ] 
   do
      # Print the message
      echo -n "$message (ynq) "
      # Now get some input
      read input
      # Test the input
      if [ -z $input ]
      then
         # Invalid input - null
         echo "INPUT ERROR: Must be y or n or q in lowercase. Please try again."
      elif [ $input = "yes" ] || [ $input = "y" ]
      then
         response="y"
         OK=1
      elif [ $input = "no" ] || [ $input = "n" ]
      then
         response="n"
         OK=1
      elif [ $input = "Help" ] || [ $input = "h" ]
      then
         Help
      elif [ $input = "q" ] || [ $input = "quit" ]
      then
         Quit
      else
         # Invalid input
         echo "INPUT ERROR: Must be y or n or q in lowercase. Please try again."
      fi
   done
}

################################################################################
# Display verbose messages in a common format                                  #
################################################################################
PrintMsg()
{
   if  [ $verbose = 1 ] && [ -n "$Msg" ]
   then
      echo "########## $Msg ##########"
      # Set the message to null
      Msg=""
   fi
}

################################################################################
# Determines whether a given package is installed. Returns 0 if true and 1 if  #
# false. Does not do file globbing but is fast. Works on DEB and RPM packages. #
################################################################################
PKGisInstalled()
{
   if [ $NAME = "CentOS" ] || [ $NAME = "Fedora" ]
   then
      # Use RPM
      # See if the RPM exists
      if  rpm -q $PackageName > /dev/null
      then
         Msg="Package $PackageName is installed"
         rc=0
      else
         Msg="Package $PackageName is NOT installed"
         rc=1
      fi
   elif [ $NAME = "LinuxMint" ]
   then
      # Use aptitude
      if aptitude show $PackageName
      then
         Msg="Package $PackageName is installed"
         rc=0
      else
         Msg="Package $PackageName is NOT installed"
         rc=1
      fi
   else
      # Invalid Distro
      Msg="Distribution not recognized. Terminating."
      error=13
      PrintMsg
      Quit $error
   fi
   PrintMsg
   return $rc
} # end PKGisInstalled

################################################################################
# Verify that this is Fedora and get the current release number.               #
################################################################################
IsFedora()
{
   if grep -i "id=Fedora" $File  > /dev/null
   then
      # This is Fedora
      NAME="Fedora"
      # Define the Distribution
      Distro=`grep PRETTY_NAME  $File | awk -F= '{print $2}' | sed -e "s/\"//g"`
      # Get the full release number
      FULL_RELEASE=`grep VERSION_ID $File | awk -F= '{print $2}'`
      # The Release version is the same as the full release number, i.e., no minor versions for Fedora
      RELEASE=$FULL_RELEASE
      rc=0
   else
      rc=1
   fi
   cd
   return $rc
} # End of IsFedora

################################################################################
################################################################################
################################################################################
################################################################################
# Main program                                                                 #
################################################################################
################################################################################
################################################################################
################################################################################
# Set initial variables
error=0
badoption=0
Msg=""
File="/etc/os-release"
MinFedoraRelease=35
TargetRelease=0
Test=0
rc=0
PackageName=""
verbose=0
NAME="unknown"
RELEASE="unknown"
version="1.0.2"
Yes=0

################################################################################
# Do some sanity checking                                                      #
################################################################################
# Set verbose on for this sanity checking
verbose=1
#---------------------------------------------------------------------------
# Check for root
if [ `id -u` != 0 ]
then
   Msg="You must be root to run this program"
   PrintMsg
   error=1
   Quit $error
fi
#---------------------------------------------------------------------------
# Check for Linux
if [[ "$(uname -s)" != "Linux" ]]
then
   Msg="This script is for Linux only -- OS detected: $(uname -s)."
   PrintMsg
   error=2
   Quit $error
fi

if IsFedora
then
   Msg="This is $NAME $RELEASE."
   PrintMsg
else
   Msg="ERROR: This is not Fedora, it is $NAME $RELEASE."
   PrintMsg
   error=3
   Quit $error
fi

#---------------------------------------------------------------------------
# Now turn verbose back off so that the -v option will take precedence
# after the input options are processed below.
verbose=0

################################################################################
# Process the input options                                                    #
################################################################################
# Get the options
while getopts ":ghvVtyr:" option; do
   case $option in
      g) # display GPL
         gpl
         Quit;;
      h) # display Help
         Help
         Quit;;
      r) # Target release version to upgrade to
         TargetRelease=$OPTARG;;
      t) # Test mode
         verbose=1
         Test=1;;
      v) # Set verbose mode
         verbose=1;;
      V) # Print the software version and exit
         echo "Version $version"
         Quit;;
      y) # Yes option ignores request for user input of YNQ
         Yes=1;;
     \?) # incorrect option
         badoption=1;;
   esac
done

################################################################################
# Check for an invalid option                                                  #
################################################################################
if [ $badoption = 1 ]
   then
   echo "ERROR: Invalid option"
   Help
   verbose=1
   error="10T"
   Quit 1
fi

################################################################################
# Do some sanity checking                                                      #
################################################################################
# Get some basic info and do a bit of setup                                    #
################################################################################
# Display the CLI command and some other data for posterity
Msg="Command options = $*"
PrintMsg

#---------------------------------------------------------------------------
if [ $verbose -eq 1 ]
then
   echo "TargetRelease = $TargetRelease  MinFedoraRelease = $MinFedoraRelease  Current Release = $RELEASE"
fi

# Check for a vaild Fedora release number argument
if [ $TargetRelease -gt $MinFedoraRelease ] && [ $RELEASE -lt $TargetRelease  ]  
then
   Msg="Upgrading from Fedora $RELEASE to Fedora $TargetRelease"
   PrintMsg
elif [ $TargetRelease -eq  0 ]
then
   Msg="You did not enter a Target Release number which must be greater than the release currently installed Fedora $RELEASE."
   PrintMsg
   Msg="Try again and be sure to enter a target release to which you want to upgrade."
   PrintMsg
   error="4"
   Quit 4
elif [ $TargetRelease -eq $RELEASE ]
then
   Msg="The release number $TargetRelease must be greater than the release currently installed Fedora $RELEASE."
   PrintMsg
   Msg="The newest Fedora release $TargetRelease is the same as the currently installed Fedora $RELEASE."
   PrintMsg
   error="5"
   Quit 5
else
   Msg="Unknown error."
   PrintMsg
   error="6"
   Quit 6
fi

################################################################################
# Exit if test mode                                                            #
################################################################################
if [ $Test -eq 1 ]
then
   Msg="Exiting program due to test mode."
   PrintMsg
   Quit
fi
################################################################################

# Install dnf if not already installed. Probably don't need this any more but ...
PackageName="dnf"
if ! PKGisInstalled
then
   Msg="Installing $PackageName"
   PrintMsg
   yum -y install $PackageName
fi

################################################################################
# Perform the actual upgrade in the following steps                            #
################################################################################
# Install the latest updates
dnf -y upgrade --refresh --best --allowerasing 
# Install the system upgrade plugin
dnf install -y  dnf-plugin-system-upgrade
# Perform the upgrade
dnf -y system-upgrade download --refresh --releasever=$TargetRelease --allowerasing
# Reboot and perform the upgrade
dnf system-upgrade reboot

Quit
exit


################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
# End of program                                                               #
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################



