Useful scripts

FreeBSD-ports-upgrade.sh
Usage examples:
Code:
FreeBSD-ports-upgrade.sh --help
Code:
FreeBSD-ports-upgrade.sh
Code:
FreeBSD-ports-upgrade.sh --jail myjail --jails-root /usr/local/vms --proxy http://user:password@myproxy:3128

FreeBSD-ports-upgrade.sh sample configuration file (when executed from scripts directory: ./FreeBSD-ports-upgrade/FreeBSD-ports-upgrade.conf or /usr/local/etc/FreeBSD-ports-upgrade/FreeBSD-ports-upgrade.conf or ~/.config/FreeBSD-ports-upgrade/FreeBSD-ports-upgrade.conf):
Code:
JailsDir='/your/jails/directory'
Proxy_String='http://your.proxy:3128'

FreeBSD-ports-upgrade.sh:
Code:
#!/bin/sh

#-------------------------------------------------------------------------#
# References
#-------------------------------------------------------------------------#
#
# man sh
# man test
# man sysexits
#
# Handbook Chapter 27.8:Updating FreeBSD with packages
# - https://docs.freebsd.org/en/books/handbook/cutting-edge/
# Handbook Chapter 17.12: Jail Upgrading
# - https://docs.freebsd.org/en/books/handbook/jails/#jail-upgrading
#
# https://stackoverflow.com/questions/592620/how-can-i-check-if-a-program-exists-from-a-bash-script
# - Test if command/programme exists/is installed
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Contributors
#-------------------------------------------------------------------------#
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Dependencies
#-------------------------------------------------------------------------#
# Bourne/POSIX shell, or Bourne/POSIX compatible shell
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Known issues
#-------------------------------------------------------------------------#
# Will upgrade FreeBSD-* as well as ports.
#-------------------------------------------------------------------------#



#-------------------------------------------------------------------------#
# Version history
#-------------------------------------------------------------------------#
version="1.0.0"
# Version 1.0.0:
# - Initial release.
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Signal Traps
#-------------------------------------------------------------------------#
cleanup ( )
{
        # cleanup code goes here
        # Cannot echo to console from within this function, perhaps to file works.
        echo "Cleaning up on exit..."
}

# [Ctrl][c]=SIGINT [Ctrl][\]=SIGQUIT
trap "cleanup" INT QUIT
#-------------------------------------------------------------------------#



#-------------------------------------------------------------------------#
# Functions
#-------------------------------------------------------------------------#
version ( )
{
    printf "%s\nVersion: %s\n" "${scriptNameExt}" "${version}"
        exit 0
}

usage-show ( )
{
        printf "%s\n" "Usage:"
        printf "%s\n" "${scriptNameExt} -v | --version"
        printf "%s\n" "${scriptNameExt} -h | --help"
    printf "%s\n" "${scriptNameExt} [[-d | --debug] debug_level] [--jail jail] [--jails-root jailsroot] [--proxy proxy]"
        printf "%s\n" ''
        printf "%s\n" "-v|--version - shows version"
        printf "%s\n" "-h|--help - shows usage"
        printf "\n"
    printf "%s\n" "Where:"
    printf "%s\n" "- 'debug_level' is the level of debug logging."
    printf "%s\n" "- 'jail' is the name of the jail to upgrade."
    printf "%s\n" "- 'jailsroot is the directory containing directories for jails."
    printf "%s\n" "- 'proxy_string' is the value to set http_proxy and https_proxy to."
    printf "%s\n" "  E.g.:"
    printf "%s\n" "    'http://proxy:3128' to prompt for proxy credentials"
    printf "%s\n" "    'http://user:passwd@proxy:3128' no prompt for proxy credentials"

    exit 64 # EX_USAGE (64) The command was used incorrectly, e.g., with the wrong number of arguments, a bad flag, a bad syntax in a parameter, or whatever.
}

command-check ( )
{
    # $1 = command to be checked for existence
    # $2 = Action: [ (exit) | continue ]
    # $3 = Message
    # $4 = Exit code

    commandCheckAction=${2:-exit}
    commandCheckMessage=${3:-${1} not available.}
    commandCheckExitCode=${4:-69} # man sysexits: 69 = service unavailable: seems closest

    if [ "$( command -v "${1}" > /dev/null 2>&1; echo "$?" )" != '0' ]
    then
        if ! [ "${commandCheckAction}" = 'continue' ]
        then
            printf "%s\n" "Error: ${commandCheckMessage}" >&2
            exit "${commandCheckExitCode}"
        else
            printf "%s\n" "Warning: ${commandCheckMessage}"
        fi
    fi
}

conf_files-process ( )
{
        if [ -f "${scriptName}/${scriptName}.conf" ] # Settings in script/product directory - presupposes run from scripts directory
        then
                . "${scriptName}/${scriptName}.conf"
        fi
        if [ -f "/usr/local/etc/${scriptName}/${scriptName}.conf" ] # FreeBSD system wide settings
        then
                . "/usr/local/etc/${scriptName}/${scriptName}.conf"
        fi
        if [ -f "$HOME/.config/${scriptName}/${scriptName}.conf" ] # User settings
        then
                . "$HOME/.config/${scriptName}/${scriptName}.conf"
        fi
}

cmdline-process ( )
{
        # Bibliography
        # https://www.grymoire.com/Unix/Sh.html#uh-96
        # - Checking for optional arguments
        # https://www.grymoire.com/Unix/Sh.html#uh-71
        # - $@ versus ${1+$@}
        # **!! First incorrect option terminates processing of command line,
        #   what is left becomes parameters.

        while :
        do
                case "$1" in
                        '--')
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                break;
                                ;;
                        -d|--debug)
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                debugLevel="${1}"
                                ;;
                        -h|--help)
                                usage-show
                                ;;
                        -l|--license)
                                license-cat;
                                ;;
                        -v|--version)
                                version
                                ;;
            '--jail')
                processedTokenCount=$((processedTokenCount + 1));
                shift;
                Jail_Name="${1}";
                ;;
            '--jails-root')
                processedTokenCount=$((processedTokenCount + 1));
                shift;
                Jails_Root="${1}";
                ;;
                        '--proxy')
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                Proxy_String="${1}";
                                ;;
                        '^-*'|'^--*')
                                ;;
                        # removing '*)' case will require '--' for "pass through" options/parameters to work
                                #   BUT: not providing the '--' will never exit option parsing - so DO NOT disable '*)' case!
                                *)
                                break;
                                ;;
                esac
                processedTokenCount=$((processedTokenCount + 1));
                shift
        done
}

proxy-set ()
{
        if [ "${Proxy_String#*'@'}" = "${Proxy_String}" ]
    then
        env-add "http_auth='basic:*'"
    fi
    env-add "http_proxy=${Proxy_String}"
    env-add "https_proxy=""${Proxy_String}"
}

env-add () {
    # ${1} = addition to script scope environment
    if [ ! "${Env}" ]
        then
        Env='env'
        fi
        Env="${Env} ${1}"
}
#-------------------------------------------------------------------------#


#-------------------------------------------------------------------------#
# Defaults
#-------------------------------------------------------------------------#
Jail_Name=''
Jails_Root='/usr/local/virtualisation/jails/containers'
Proxy_String=''
rootdir_cmd=''
requiredDependencies='bectl' # list of required programmes (exit script if missing)
optionalDependencies='' # list of optional programmes (continue script if missing)
#-------------------------------------------------------------------------#


#-------------------------------------------------------------------------#
# main
#-------------------------------------------------------------------------#
# Check for optional commands/programmes
if [ -n "${optionalDependencies}" ]
then
        for prog in ${optionalDependencies}
        do
        command-check "${prog}" 'continue'
        done
fi
# Check for required commands/programmes
if [ -n "${requiredDependencies}" ]
then
        for prog in ${requiredDependencies}
        do
        command-check "${prog}" 'exit'
        done
fi

# script name:
scriptNameExt="${0##*/}"
# script name minus extension:
scriptName="${scriptNameExt%.sh}"

# get script/product default options (stored as global variables)
conf_files-process

# override script/product default configuration with options if specified
processedTokenCount=0
cmdline-process "$@"
shift $((processedTokenCount)) # must remove processed tokens from "$@" outside function

# set proxy URL if specified:
if [ -n "${Proxy_String}" ]
then
        proxy-set
fi

if [ -n "${Jail_Name}" ]
then # upgrading jail packages
        rootdir_cmd="--rootdir ${Jails_Root}/${Jail_Name}"
        # create jail backup:
        tmpZFSdataset=$( zfs list | grep "${Jails_Root}$" | awk '{print $1}' )
        zfs snapshot -r "${tmpZFSdataset}/${Jail_Name}@ports-upgrade-$( uname -r ).$( date '+%FT%H%M%S%Z' )"
    if [ "$?" -ne "0" ]
    then
        printf "%s\n" "Error creating backup snapshot."
        printf "%s\n" "It is recommended a suitable snapshot be created manually before proceeding."
        read -p "Do you wish to continue now? [y/N]" -r continue
        if ! [ "${continue}" = "y" -o "${continue}" = "Y" ]
        then
            exit 73 # EX_CANTCREAT (73)
        fi
    fi
else # upgrading host packages
    # create boot environment backup
        bectl create -r "ports-upgrade-$( uname -r ).$( date '+%FT%H%M%S%Z' )"
    if [ "$?" -ne "0" ]
    then
        printf "%s\n" "Error creating backup boot environment."
        printf "%s\n" "It is recommended a boot environment be created manually before proceeding."
        read -p "Do you wish to continue now? [y/N]" -r continue
        if ! [ "${continue}" = "y" -o "${continue}" = "Y" ]
        then
            exit 73 # EX_CANTCREAT (73)
        fi
    fi
fi

# upgrade all ports including FreeBSD-* ports ("base" operating system):
${Env} pkg ${rootdir_cmd} upgrade

# Check for Failed Configuration Updates:
find /etc /usr/local/etc -name '*.pkgnew' -ls
printf "\n"

# reboot
if [ -n "${Jail_Name}" ]
then
        printf "%s" "Ports upgrade complete. Do you wish to restart jail ${Jail_Name} now? [y/N]: "
else
        printf "%s" "Ports upgrade complete. Do you wish to reboot now? [y/N]: "
fi
read -r continue
if [ "${continue}" = "y" -o "${continue}" = "Y" ]
then
        if [ -n "${Jail_Name}" ]
        then
                service jail restart "${Jail_Name}"
        else
                shutdown -r now 'Rebooting after upgrading.'
        fi
fi

printf "\n"

exit 0
#-------------------------------------------------------------------------
 
FreeBSD-version-upgrade.sh
Usage examples:
Code:
FreeBSD-version-upgrade.sh --help
Code:
FreeBSD-version-upgrade.sh --new-version 1501000
Code:
FreeBSD-version-upgrade.sh --jail myjail --jails-root /usr/local/vms --proxy http://user:password@myproxy:3128 --new-version 1501000

FreeBSD-version-upgrade.sh sample configuration file (when executed from scripts directory: .FreeBSD-version-upgrade/FreeBSD-version-upgrade.conf or /usr/local/etc/FreeBSD-version-upgrade/FreeBSD-version-upgrade.conf or ~/.config/FreeBSD-version-upgrade/FreeBSD-version-upgrade.conf):
Code:
JailsDir='/your/jails/directory'
Proxy_String='http://your.proxy:3128'

FreeBSD-version-upgrade.sh:
Code:
#!/bin/sh

#-------------------------------------------------------------------------#
# References
#-------------------------------------------------------------------------#
#
# man sh
# man test
# man sysexits
#
# Handbook Chapter 27.8:Updating FreeBSD with packages
# - https://docs.freebsd.org/en/books/handbook/cutting-edge/
# Handbook Chapter 17.12: Jail Upgrading
# - https://docs.freebsd.org/en/books/handbook/jails/#jail-upgrading
# FreeBSD 15.1-RELEASE Upgrading Instructions -> Upgrading with Base System Packages
# - https://www.freebsd.org/releases/15.1R/upgrading/
#
# https://stackoverflow.com/questions/592620/how-can-i-check-if-a-program-exists-from-a-bash-script
# - Test if command/programme exists/is installed
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Contributors
#-------------------------------------------------------------------------#
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Dependencies
#-------------------------------------------------------------------------#
# Bourne/POSIX shell, or Bourne/POSIX compatible shell
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Known issues
#-------------------------------------------------------------------------#
#-------------------------------------------------------------------------#



#-------------------------------------------------------------------------#
# Version history
#-------------------------------------------------------------------------#
version="1.0.0"
# Version 1.0.0:
# - Initial release.
#-------------------------------------------------------------------------#

#-------------------------------------------------------------------------#
# Signal Traps
#-------------------------------------------------------------------------#
cleanup ( )
{
        # cleanup code goes here
        # Cannot echo to console from within this function, perhaps to file works.
        echo "Cleaning up on exit..."
}

# [Ctrl][c]=SIGINT [Ctrl][\]=SIGQUIT
trap "cleanup" INT QUIT
#-------------------------------------------------------------------------#



#-------------------------------------------------------------------------#
# Functions
#-------------------------------------------------------------------------#
version ( )
{
    printf "%s\nVersion: %s\n" "${scriptNameExt}" "${version}"
        exit 0
}

usage-show ( )
{
        printf "%s\n" "Usage:"
        printf "%s\n" "${scriptNameExt} -v | --version"
        printf "%s\n" "${scriptNameExt} -h | --help"
        printf "%s\n" "${scriptNameExt} [[-d | --debug] debug_level] [--jail jail] [--jails-root jailsroot] [--proxy proxy] --new-version version"
        printf "%s\n" ''
        printf "%s\n" "-v|--version - shows version"
        printf "%s\n" "-h|--help - shows usage"
        printf "\n"
    printf "%s\n" "Where:"
    printf "%s\n" "- 'debug_level' is the level of debug logging."
    printf "%s\n" "- 'jail' is the name of the jail to upgrade."
    printf "%s\n" "- 'jailsroot is the directory containing directories for jails."
    printf "%s\n" "- 'proxy_string' is the value to set http_proxy and https_proxy to."
    printf "%s\n" "  E.g.:"
    printf "%s\n" "    'http://proxy:3128' to prompt for proxy credentials"
    printf "%s\n" "    'http://user:passwd@proxy:3128' no prompt for proxy credentials"
    printf "%s\n" "- 'version' is the version to upgrade to, e.g. '1501000'."
}

command-check ( )
{
    # $1 = command to be checked for existence
    # $2 = Action: [ (exit) | continue ]
    # $3 = Message
    # $4 = Exit code

    commandCheckAction=${2:-exit}
    commandCheckMessage=${3:-${1} not available.}
    commandCheckExitCode=${4:-69} # man sysexits: 69 = service unavailable: seems closest

    if [ "$( command -v "${1}" > /dev/null 2>&1; echo "$?" )" != '0' ]
    then
        if ! [ "${commandCheckAction}" = 'continue' ]
        then
            printf "%s\n" "Error: ${commandCheckMessage}" >&2
            exit "${commandCheckExitCode}"
        else
            printf "%s\n" "Warning: ${commandCheckMessage}"
        fi
    fi
}

conf_files-process ( )
{
        if [ -f "${scriptName}/${scriptName}.conf" ] # Settings in script/product directory - presupposes run from scripts directory
        then
                . "${scriptName}/${scriptName}.conf"
        fi
        if [ -f "/usr/local/etc/${scriptName}/${scriptName}.conf" ] # FreeBSD system wide settings
        then
                . "/usr/local/etc/${scriptName}/${scriptName}.conf"
        fi
        if [ -f "$HOME/.config/${scriptName}/${scriptName}.conf" ] # User settings
        then
                . "$HOME/.config/${scriptName}/${scriptName}.conf"
        fi
}

cmdline-process ( )
{
        # Bibliography
        # https://www.grymoire.com/Unix/Sh.html#uh-96
        # - Checking for optional arguments
        # https://www.grymoire.com/Unix/Sh.html#uh-71
        # - $@ versus ${1+$@}
        # **!! First incorrect option terminates processing of command line,
        #   what is left becomes parameters.

        while :
        do
                case "$1" in
                        '--')
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                break;
                                ;;
                        -d|--debug)
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                debugLevel="${1}"
                                ;;
                        -h|--help)
                                usage-show
                                ;;
                        -l|--license)
                                license-cat;
                                ;;
                        -v|--version)
                                version
                                ;;
                        '--jail')
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                Jail_Name="${1}";
                                ;;
            '--jails-root')
                processedTokenCount=$((processedTokenCount + 1));
                shift;
                Jails_Root="${1}";
                ;;
                        '--new-version')
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                New_Version="${1}";
                                ;;
                        '--proxy')
                                processedTokenCount=$((processedTokenCount + 1));
                                shift;
                                Proxy_String="${1}";
                                ;;
                        '^-*'|'^--*')
                                ;;
                        # removing '*)' case will require '--' for "pass through" options/parameters to work
                                #   BUT: not providing the '--' will never exit option parsing - so DO NOT disable '*)' case!
                                *)
                                break;
                                ;;
                esac
                processedTokenCount=$((processedTokenCount + 1));
                shift
        done
}

proxy-set ()
{
        if [ "${Proxy_String#*'@'}" = "${Proxy_String}" ]
    then
        env-add "http_auth='basic:*'"
    fi
    env-add "http_proxy=${Proxy_String}"
    env-add "https_proxy=""${Proxy_String}"
}

env-add () {
    # ${1} = addition to script scope environment
    if [ ! "${Env}" ]
        then
        Env='env'
        fi
        Env="${Env} ${1}"
}
#-------------------------------------------------------------------------#


#-------------------------------------------------------------------------#
# Defaults
#-------------------------------------------------------------------------#
Jail_Name=''
Jails_Root='/usr/local/virtualisation/jails/containers'
Proxy_String=''
rootdir_cmd=''
New_Version=''
requiredDependencies='bectl' # list of required programmes (exit script if missing)
optionalDependencies='' # list of optional programmes (continue script if missing)
#-------------------------------------------------------------------------#


#-------------------------------------------------------------------------#
# main
#-------------------------------------------------------------------------#
# Check for optional commands/programmes
if [ -n "${optionalDependencies}" ]
then
        for prog in ${optionalDependencies}
        do
        command-check "${prog}" 'continue'
        done
fi
# Check for required commands/programmes
if [ -n "${requiredDependencies}" ]
then
        for prog in ${requiredDependencies}
        do
        command-check "${prog}" 'exit'
        done
fi

# script name:
scriptNameExt="${0##*/}"
# script name minus extension:
scriptName="${scriptNameExt%.sh}"

# get script/product default options (stored as global variables)
conf_files-process

# override script/product default configuration with options if specified
processedTokenCount=0
cmdline-process "$@"
shift $((processedTokenCount)) # must remove processed tokens from "$@" outside function

# New_Version is compulsory
if [ -z "${New_Version}" ]
then
        printf "%s\n" "Version to upgrade is compulsory, e.g. 1501000. Aborting upgrade."
        usage-show
        exit 64 # EX_USAGE (64) The command was used incorrectly, e.g., with the wrong number of arguments, a bad flag, a bad syntax in a parameter, or whatever.
fi

# set proxy URL if specified:
if [ -n "${Proxy_String}" ]
then
        proxy-set
fi

if [ -z "${Jail_Name}" ]
then # upgrading host
        printf "%s\n" "Note: you will need a second console/terminal during this script execution for upgrading bootloader(s)."
        printf "%s\n" "Connect to second console before proceeding."
        printf "%s" "Ready to continue? [y/N]: "
        read -r continue
        if ! [ "${continue}" = "y" -o "${continue}" = "Y" ]
        then
        printf "%s\n" 'Aborting upgrade.'
        fi
fi

if [ -n "${Jail_Name}" ]
then # upgrading jail packages
    rootdir_cmd="--rootdir ${Jails_Root}/${Jail_Name}"
    # create jail backup:
    tmpZFSdataset=$( zfs list | grep "${Jails_Root}$" | awk '{print $1}' )
    zfs snapshot -r "${tmpZFSdataset}/${Jail_Name}@upgrade-$( uname -r ).$( date '+%FT%H%M%S%Z' )"
    if [ "$?" -ne "0" ]
    then
        printf "%s\n" "Error creating backup snapshot."
        printf "%s\n" "It is recommended a suitable snapshot be created manually before proceeding."
        read -p "Do you wish to continue now? [y/N]" -r continue
        if ! [ "${continue}" = "y" -o "${continue}" = "Y" ]
        then
            exit 73 # EX_CANTCREAT (73)
        fi
    fi
else # upgrading host packages
    # create boot environment backup
    bectl create -r "upgrade-$( uname -r ).$( date '+%FT%H%M%S%Z' )"
    if [ "$?" -ne "0" ]
    then
        printf "%s\n" "Error creating backup boot environment."
        printf "%s\n" "It is recommended a boot environment be created manually before proceeding."
        read -p "Do you wish to continue now? [y/N]" -r continue
        if ! [ "${continue}" = "y" -o "${continue}" = "Y" ]
        then
            exit 73 # EX_CANTCREAT (73)
        fi
    fi
fi

# ensure system is up to date:
${Env} pkg ${rootdir_cmd} upgrade -r FreeBSD-base
# Upgrade the Base System:
${Env} pkg -oABI=FreeBSD:15:$(uname -p) -oOSVERSION="${New_Version}" ${rootdir_cmd} upgrade -r FreeBSD-base
# Upgrade Kernel Modules:
${Env} pkg ${rootdir_cmd} upgrade -r FreeBSD-ports-kmods
printf "\n"

# Check for Failed Configuration Updates:
find /etc /usr/local/etc -name '*.pkgnew' -ls
printf "\n"

if [ -z "${Jail_Name}" ]
then # Upgrade the Boot Loader:
        printf "%s\n" "In separate console upgrade bootloader:"
        printf "%s\n" "Current bootloader: sysctl machdep.bootmethod: $( sysctl machdep.bootmethod )"
        printf: "%s\n" "If UEFI and BIOS boot then update both:"
        printf "- %s\n" "https://www.freebsd.org/releases/15.1R/upgrading/#upgrade-loader-uefi"
        printf "- %s\n" "https://www.freebsd.org/releases/15.1R/upgrading/#upgrade-loader-bios"
        printf "\n"
fi

# reboot
if [ -n "${Jail_Name}" ]
then
    printf "%s" "Upgrade complete. Do you wish to restart jail ${Jail_Name} now? [y/N]: "
else
    printf "%s" "Upgrade complete. Do you wish to reboot now? [y/N]: "
fi
read -r continue
if [ "${continue}" = "y" -o "${continue}" = "Y" ]
then
    if [ -n "${Jail_Name}" ]
    then
        service jail restart "${Jail_Name}"
    else
        shutdown -r now 'Rebooting after upgrading.'
    fi
fi

printf "\n"

exit 0
#-------------------------------------------------------------------------
 
Back
Top