scripts/app/check.forticlient.update

330 lines
10 KiB
Plaintext
Raw Permalink Normal View History

#!/bin/sh
# Purpose {{{
## Create a temp file (to monitor) if an upgrade is available for Forticlient
## from official website.
## Get version number from forticlient_vpn package link :
## https://www.fortinet.com/fr/support/product-downloads#vpn
## It's based on .deb package installation to check the current version.
## It can also compare the current available version in APT repositories
## if "repo" is given as first argument.
## If a new version is available, the script will try to download it.
## How-to use {{{
### 1. Create a cron job, eg:
#00 20 * * * root /opt/repos/ipr.scripts/app/check.forticlient.update
### 2-1 Create a cron job to compare the version available in an APT repository:
#00 20 * * * root /opt/repos/ipr.scripts/app/check.forticlient.update --mode repo
### 2. Monitor the temp file: /tmp/.forticlient.upgrade
# Or enable MAILTO in cronjob and edit the script to print a message.
# Or send a mail.
# …
## }}}
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
PROGDIR=$(readlink -m $(dirname "${0}")); readonly PROGDIR
ARGS="${*}"; readonly ARGS
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=0
## Export DEBUG for sub-script
export DEBUG
## Default values for some vars
CHECK_MODE_DEFAULT="file"
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat << HELP
usage: $PROGNAME [check_mode] [-m|-d|-h]
Compare current version of an installed Forticlient and the last available.
EXAMPLES:
- Compare the current version of Forticlient installed from a .deb file
${PROGNAME}
${PROGNAME} --mode file
- Compare the current version of Forticlient available in the APT repo
${PROGNAME} repo
${PROGNAME} --mode repo
OPTIONS:
-m,--mode
Set the check_mode to use to get current version of Forticlient client
Available mode :
* repo
* file (default behaviour)
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
HELP
}
# }}}
debug_message() { # {{{
local_debug_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_debug_message}"
unset local_debug_message
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print message
printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}"
unset local_error_message
exit "${local_error_code:=66}"
}
# }}}
is_var_empty() { # {{{
## Return False by default
return_var_empty="1"
## Total number of variables to test
local_total_var_empty="${#}"
loop_count_var_empty="0"
## While it remains a variable to test
while [ "${local_total_var_empty}" -gt "${loop_count_var_empty}" ]; do
debug_message "is_var_empty \
Test var: ${RED}${1}${COLOR_DEBUG}."
### Test if this is empty and set return value to True
[ -z "${1}" ] && return_var_empty="0"
### Increase the number of tested variables
loop_count_var_empty=$((loop_count_var_empty+1))
### Shift to the next variable
shift
done
unset local_total_var_empty
unset loop_count_var_empty
return "${return_var_empty}"
}
# }}}
define_vars() { # {{{
## If check_mode wasn't defined (argument) {{{
## Use default value
is_var_empty "${check_mode}" \
&& debug_message "define_vars Use default value (${CHECK_MODE_DEFAULT}) for check_mode variable." \
&& check_mode="${CHECK_MODE_DEFAULT}"
## }}}
## Get forticlient_current_version according to the check_mode {{{
case "${check_mode}" in
"repo" ) ## Check forticlient version from repository
forticlient_current_version=$(apt-cache policy -- forticlient | awk '/Candidate:/ {print $2}' | sed 's/.:\(.*\)-.*/\1/')
;;
"file" ) ## Check forticlient version from installed .deb file
forticlient_current_version=$(dpkg --list -- forticlient | awk '/^ii *forticlient/ {print $3}' | sed 's/.:\(.*\)-.*/\1/')
;;
* ) ## unknow mode
error_message "define_vars Invalid check mode: ${check_mode}" 1
;;
esac
## If forticlient_current_version is empty
is_var_empty "${forticlient_current_version}" \
&& error_message "define_vars Error with forticlient_current_version variable (${forticlient_current_version})" 2
## }}}
## Forticlient vars for new version {{{
## Fortinet offer "always" the same URL to download .deb package.
## This URL can be expanded to get package version
forticlient_new_version_expanded_url=$(curl --silent https://unshorten.me/s/https://links.fortinet.com/forticlient/deb/vpnagent)
forticlient_new_version=$(echo "${forticlient_new_version_expanded_url}" | sed -e 's/http.*forticlient_vpn_\(.*\)_amd64.deb/\1/')
is_var_empty "${forticlient_new_version_expanded_url}" "${forticlient_new_version}" \
&& error_message "define_vars Error with new version variables (forticlient_new_version_expanded_url: ${forticlient_new_version_expanded_url} ; forticlient_new_version: ${forticlient_new_version})." 3
## }}}
## Vars for temp files
forticlient_new_version_file="/tmp/.forticlient.upgrade"
forticlient_new_pkg_path="/tmp/forticlient_${forticlient_new_version}_amd64.deb"
forticlient_tmp_pkg_path="/tmp/.forticlient_${forticlient_new_version}_amd64.deb"
}
# }}}
is_version_greater_than() { # {{{
first_value="${1}"
value_to_compare="${2}"
## Return False by default
return_is_version_greater_than="1"
debug_message "is_version_greater_than \
Is first value (${first_value}) greater than the second value (${value_to_compare})."
if printf '%s\n' "${first_value}" "${value_to_compare}" | sort --check=quiet --version-sort; then
debug_message "is_version_greater_than ${first_value} <= ${value_to_compare} ."
return_is_version_greater_than="1"
else
debug_message "is_version_greater_than ${first_value} > ${value_to_compare} ."
return_is_version_greater_than="0"
fi
unset first_value
unset value_to_compare
return "${return_is_version_greater_than}"
}
# }}}
main() { # {{{
define_vars
# Behaviour can be tested by overriding this variable
#forticlient_current_version="7.0.0.0000"
#forticlient_current_version="${forticlient_new_version}"
#forticlient_current_version="9.9.9.9999"
if is_version_greater_than "${forticlient_new_version}" "${forticlient_current_version}"; then
debug_message "Test version \
New version (${forticlient_new_version}) seems more recent than the current one (${forticlient_current_version})."
## If it doesn't already exists, download the package for this new version
if [ ! -f "${forticlient_new_pkg_path}" ]; then
debug_message "Deb file \
Download .deb file from fortinet.com to ${forticlient_new_pkg_path} ."
wget --quiet https://repo.fortinet.com/repo/7.0/debian/pool/non-free/f/forticlient/forticlient_"${forticlient_new_version}"_amd64.deb --output-document="${forticlient_new_pkg_path}"
fi
# Verify downloaded package
# Check the version from dpkg info {{{
forticlient_dpkg_version=$(dpkg --info -- "${forticlient_new_pkg_path}" | awk '/ Version/ { print $2 }')
if [ "${forticlient_dpkg_version}" = "${forticlient_new_version}" ]; then
debug_message "Check dpkg version \
New version and .deb file informations are similar."
## Create a temp file to monitor
touch -- "${forticlient_new_version_file}"
printf '\e[1;35m%-6s\e[m\n' "An upgrade is available for forticlient (current: ${forticlient_current_version}): ${forticlient_new_version}." >> "${forticlient_new_version_file}"
## Exit
exit 0
else
debug_message "Check dpkg version \
New version and .deb file informations mismatch, don't need to go further."
# }}}
# Remove useless file {{{
## Ensure to remove the file to monitor
rm --force -- "${forticlient_new_version_file}"
## Keep a record of the downloaded package because as a new release might come soon
mv --force -- "${forticlient_new_pkg_path}" "${forticlient_tmp_pkg_path}"
## Exit
exit 0
fi
# }}}
else
debug_message "Test version The current version is the same or is more recent than the available one."
## Ensure to remove any temp file and useless .deb file
rm --force -- "${forticlient_new_version_file}" "${forticlient_new_pkg_path}" "${forticlient_tmp_pkg_path}"
## Exit
exit 0
fi
# }}}
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to arguments
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
## If the first argument is not an option
if ! printf -- '%s' "${1}" | grep --quiet --extended-regexp -- "^-+";
then
## Consider it as the mode to use to get current forticlient version
check_mode="${1}"
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
fi
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1}" | grep --quiet --extended-regexp -- "^-+"; do
case "${1}" in
-m|--mode ) ## Define check_mode
## Move to the next argument
shift
## Define var
readonly check_mode="${1}"
;;
-d|--debug ) ## debug
DEBUG=0
;;
-h|--help ) ## help
usage
## Exit after help informations
exit 0
;;
-- ) ## End of options list
## End the while loop
break
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "Arguments management \
${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "Arguments management \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "Arguments management \
No arguments/options to manage."
fi
# }}}
main
exit 255