#!/bin/sh -e

##########################################################################
#   Script description:
#       Upgrade the base system to a new release.
#       
#   History:
#   Date        Name        Modification
#   2020?       Jason Bacon Begin
##########################################################################

usage()
{
    printf "Usage: $0 [release]\n"
    exit 1
}


##########################################################################
#   Function description:
#       Run freebsd-update on next reboot.  The update script removes
#       itself after successful completion.
#       
#   History:
#   Date        Name        Modification
#   2023-03-10  J Bacon     Begin
##########################################################################

update_on_boot()
{
    rc_dir=/etc/rc.local.d
    update_script=freebsd-update-install.sh
    
    mkdir -p $rc_dir
    cat << EOM > $rc_dir/$update_script
#!/bin/sh -e

# Bugs in freebsd-update may cause non-critical failures.
# Allow auto-update-system to run anyway, otherwise the system won't
# function after major upgrades, where packages need to be reinstalled
# for a new major OS version.
/usr/sbin/freebsd-update install || true
/usr/local/sbin/auto-update-system --defaults
rm -f $rc_dir/$update_script

EOM
    chmod 755 $rc_dir/$update_script
    
    if ! fgrep -q $rc_dir /etc/rc.local; then
	cat << EOM >> /etc/rc.local

# Added by auto-upgrade-base
for script in $rc_dir/*; do
    /bin/sh \$script
done
# End auto-upgrade-base addition
EOM
    fi
    
    return 0
}


##########################################################################
#   Function description:
#       Pause until user presses return
##########################################################################

pause()
{
    local junk
    
    printf "Press return to continue..."
    read junk
}


##########################################################################
#   Main
##########################################################################

auto-root-check $0

cat << EOM

The system should be fully up-to-date on the current release before
upgrading the base.  Run "auto-update-system --yes" if you have not
updated recently.

EOM
pause

case $(auto-ostype) in
FreeBSD)
    case $# in
    0)
	current_release=$(uname -r)
	version=${current_release%-*}
	branch=${current_release#*-}
	branch=${branch%%-*}    # Remove -p*
	major=${version%.*}
	minor=${version#*.}
	if [ $branch = RELEASE ]; then
	    next_release=$major.$(($minor + 1))-$branch
	elif echo $branch | grep -q BETA; then
	    beta=${branch#BETA}
	    next_release=$version-BETA$(($beta + 1))
	elif echo $branch | grep -q RC; then
	    rc=${branch#RC}
	    next_release=$version-RC$(($rc + 1))
	else
	    next_release=$major.$minor-$branch
	fi
	printf "New release? [$next_release] "
	read release
	if [ -z "$release" ]; then
	    release=$next_release
	fi
	;;
    1)
	release=$1
	;;
    esac
    
    new_version=${release%-*}
    new_minor=${new_version#*.}
    echo $new_version $new_minor
    if [ $new_minor -gt 0 ]; then
	new_major=${new_version%.*}
	previous_release=$new_major.$(($new_minor - 1))
	more << EOM

			    ======== Caution ========

The FreeBSD project currently does not guarantee KBI (kernel binary interface)
compatibility across point releases, and does not build binary packages
on release x.y until x.(y-1) has reached end-of-life (EOL).
I.e., packages from x.(y-1) are used on x.y until x.(y-1) EOL.

As result, installing kernel modules using "pkg" on FreeBSD $release
may cause problems until FreeBSD $previous_release has reached end-of-life,
at which time package building is switched to FreeBSD $release.

To avoid problems with binary packages, wait until $previous_release
reaches end-of-life before upgrading to $release.

EOM
    fi
    
    more << EOM

			    ======== Warning ========

Using the upgrade process to switch to a new release of the OS is not the
cleanest way to upgrade.  Any corruption in the filesystem or configuration
files caused by power outages or human error will likely remain after the
upgrade, as will "bit rot", the degradation of data on storage media due
to physical flaws or other causes.

Many IT experts argue that a filesystem should be wiped away and recreated
once every year or two in order to avoid accumulating hidden problems.

You may want to consider instead backing up your important files (e.g.
documents, source code, configuration files under /etc and /usr/local/etc)
and doing a fresh install to ensure that you end up with a pristine system.
This process also helps eliminate junk files and free up disk space.

Minor upgrades (e.g. from 13.0 to 13.1) are generally safer than major
upgrades (12.3 to 13.1), but a fresh install always results in the cleanest
system.  Doing fresh installs frequently is also good practice to prepare
you for times when you have no choice (new systems, disk failures).

Note also that you may need to manually edit some configuration files
before proceeding with the upgrade.

EOM
    while [ 0"$resp" != 0"yes" ] && [ 0"$resp" != 0"no" ]; do
	printf "Proceed? yes/no "
	read resp
    done
    if [ $resp = yes ]; then
	freebsd-update upgrade -r $release
	resp=""
	while [ 0"$resp" != 0"yes" ] && [ 0"$resp" != 0"no" ]; do
	    printf "Install updates? yes/no "
	    read resp
	done
	if [ $resp = yes ]; then
	    # Restart sshd immediately in case API changes broken running daemon
	    # Otherwise we may lose access when upgrading remotely
	    freebsd-update install
	    service sshd restart || true

	    cat << EOM

The system must be rebooted to load the new kernel.  If you choose to
reboot now, "freebsd-update install" and "pkg upgrade" will run
automatically to complete the update.  If you choose not to reboot
now, you must run "freebsd-update install" at mininum to complete
the base update. For major upgrades, it will be necessary to update
installed packages as well.

EOM
	    resp=""
	    while [ 0"$resp" != 0"yes" ] && [ 0"$resp" != 0"no" ]; do
		printf "Reboot now? yes/no "
		read resp
	    done
	    if [ $resp = yes ]; then
		update_on_boot
		shutdown -r now
	    fi
	fi
    fi
    ;;
    
*)
    auto-unsupported-os $0
    exit 1
    ;;

esac
