Howto: be notified of FreeBSD upgrades, security updates and package updates at login

Hello all FreeBSD users,

At the invitation of Crivens, I repost here the little script I've come up with and which received improvements from the community (thanks SirDice, unitrunker, emmex).

Context: the idea was to obtain information about FreeBSD upgrades, security updates and package updates right at login.
It's something I find has been lacking for years for the average self-hosted FreeBSD user like me who occasionally logs in to his server to check if everything's going well, perform package upgrades etc, and wants to stay up to date with the latest version available of the operating system. Yet AFAIK (unless I missed something in the documentation for all these years, which is totally possible) there's no simple way for the system to tell you "hey there, a new production version is available, you should start considering upgrading" right at login. I know I could subscribe to a mailing list to be notified directly in my mailbox, but these emails rarely come at a moment where I'm ready to address this issue, and I'd rather be notified of that when I login to my server - because that's exactly when I'm available to perform routine maintenance tasks.

The following script (which I currently use on my FreeBSD machines) answers this need ; I commit myself to come back and post updates and fixes whenever it'll be necessary.

How to use : paste the following lines in a file, make it executable (chmod +x file) and append a line in your ~/.profile (or whatever login script your shell uses) to call it at login time.

Code:
#!/usr/bin/env sh

# let's do an automatic update check (use http as long as it's supported, https also works)
_ICON_THUMBSUP="\xf0\x9f\x91\x8d"
_ICON_WARNING="\xe2\x9a\xa0\xef\xb8\x8f"
_ICON_NOTICE="\xf0\x9f\x92\xac"
_ICON_WAIT1="\xe2\x8f\xb3"
_ICON_WAIT2="\xe2\x8c\x9b"
echo ""
printf "  ${_ICON_WAIT1}  Checking for operating system updates, please wait... "
_CUR_MMN="$(freebsd-version|awk -F- '{print $1}')"
_CUR_VER="$(freebsd-version)"
_AVL_MMN="$(HTTP_TIMEOUT=3 fetch -qo - "http://www.freebsd.org" 2>/dev/null|tr -d '\n'|sed -E -e 's/<\/?(a|span)[^>]*>//g' -e 's/<\/?(br|li|p|div)>/\n/g'|grep "Production:"|tr ',' ' '|awk '{print $NF}')"
_AVL_VER="${_AVL_MMN}-$(HTTP_TIMEOUT=3 fetch -qo - "http://cgit.freebsd.org/src/plain/sys/conf/newvers.sh?h=releng/${_AVL_MMN}" 2>/dev/null|grep "^BRANCH="|cut -d'"' -f2)"
if [ -z "${_AVL_MMN}" ]; then
    printf "\r  ${_ICON_WARNING}  Automatic update check failed (error retrieving the latest production version from www.freebsd.org).\n"
elif [ -z "$(echo "${_AVL_VER}"|grep "RELEASE")" ]; then
    printf "\r  ${_ICON_WARNING}  Automatic update check failed (error retrieving the latest patchlevel version from cgit.freebsd.org).\n"
elif [ "_${_CUR_VER}" = "_${_AVL_VER}" ]; then
    printf "\r  ${_ICON_WAIT2}  Checking for available package updates, please wait... "
    _PKG_CNT="$(pkg upgrade -n|grep -E -o "^The following [0-9]+"|grep -E -o "[0-9]+"||echo "0")"
    if [ "${_PKG_CNT}" -gt 0 ]; then
        printf "\r  ${_ICON_NOTICE}  You have \e[1;37m${_PKG_CNT}\e[0m outdated package(s). Consider using \e[33mpkg(8) upgrade\e[0m.\n"
    else
        printf "\r  ${_ICON_THUMBSUP}  Your system is up to date. Congratulations!           \n"
    fi
elif [ "_${_CUR_MMN}" = "_${_AVL_MMN}" ]; then
    printf "\r  ${_ICON_WARNING}  A security update is available: \e[1;37m${_AVL_VER}\e[0m. Consider using \e[33mfreebsd-update(8)\e[0m.\n"
else
    printf "\r  ${_ICON_WARNING}  A new FreeBSD version is available: \e[1;37m${_AVL_VER}\e[0m. Consider using \e[33mfreebsd-update(8)\e[0m.\n"
fi
unset _AVL_VER _AVL_MMN _CUR_VER _CUR_MMN _PKG_CNT _ICON_WAIT2 _ICON_WAIT1 _ICON_NOTICE _ICON_WARNING _ICON_THUMBSUP
echo ""

Then, each time you log in you can be notified of OS security updates, OS upgrades and package updates.

How it works:
Basically [...], it simply fetches the www.freebsd.org website index, parses the returned HTML and looks at the number that's right after "Production:" in the middle of the page that tells the visitor which is the latest supported production release. Then it does a second query to cgit.freebsd.org to find out the current patchlevel for this version out of the sys/conf/newvers.sh script. It then assembles that data in a variable, and compares it with the current version string that the "freebsd-version" command returns. If the major/minor part differs, it suggests an OS upgrade. If the patchlevel differs, it tells you a security update is available. And if an error occured while trying to retrieve the latest available version tag, it tells you where it happened.

Only one single line of output will be displayed : each intermediate message is erased by the next one. It does not flood your terminal.

Extra candy: if your SSH terminal supports Unicode emoticons (e.g. macOS' Terminal.app) you get color icons prefixed in the message lines printed by the script :

⏳ Checking for operating system updates, please wait...

⌛ Checking for available package updates, please wait...

⚠️ A security update is available: 13.1-RELEASE-p2. Consider using freebsd-update(8).

💬 You have 15 outdated package(s). Consider using pkg(8) upgrade.

👍 Your system is up to date. Congratulations!

Of course, if your terminal doesn't support Unicode, or you prefer ASCII-only output, empty these variables in the script, or "simplify" them, for example like this:
Code:
_ICON_THUMBSUP=":-)"
_ICON_WARNING="/!\\"
_ICON_NOTICE="/!\\"
_ICON_WAIT1="[.]"
_ICON_WAIT2="[:]"

TBH I'm not 100% happy with the HTML parsing it does but I wanted something simple, light, and fast. This does the job. It would be ideal if FreeBSD.org defined some sort of stable API to get this information in one single HTTP request. Should that be decided one day, please notify me and I'll make the necessary changes.

Thanks to all the contributors so far. Comments, suggestions, and contributions/improvements are welcome !
 
Back
Top