diff options
| author | mail_redacted_for_web | 2026-01-15 14:53:20 +0100 |
|---|---|---|
| committer | mail_redacted_for_web | 2026-01-15 14:53:20 +0100 |
| commit | 69d0cd8cd9ca9fba5cfa77cfd1332b4aa98e8b45 (patch) | |
| tree | f1f86a22c418c03dd34f5e59986e5229035b8b48 /bin/os-patching-adhoc | |
| parent | 4f0b5cb177f98c7f1d80504f94eeba94f721d2de (diff) | |
| download | os-patch-69d0cd8cd9ca9fba5cfa77cfd1332b4aa98e8b45.tar.bz2 | |
Adding ad-hoc patch script, readme, and licence informationv0.9.0
Diffstat (limited to 'bin/os-patching-adhoc')
| -rw-r--r-- | bin/os-patching-adhoc | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/bin/os-patching-adhoc b/bin/os-patching-adhoc new file mode 100644 index 0000000..ebe8318 --- /dev/null +++ b/bin/os-patching-adhoc @@ -0,0 +1,253 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1091 + +# Ad-hoc script for just patching the system. + +# Environment variables: +# RKHUNTER - will be set to 0 if rkhunter exists and this variable is not set. +# Setting it to 1 will skip using rkhunter. +# NEEDREST - will be set to 0 if needrestart exists and this variable is not set. +# Setting it to 1 will skip using needrestart or any other helper +# like dnf needs-restarting or zypper needs-rebooting / zypper ps. + +# os_patching made by albatrossflavour et al., binary: +OSPBIN='/usr/local/bin/os_patching_fact_generation.sh' + +. /etc/os-release || exit 1 + +# Debian act as if ID_LIKE wasn't necessary if ID == ID_LIKE. Great job, guys. +if [ "$ID" = "debian" ]; then + ID_LIKE="debian" +fi + + +# 0. Internal helpers +hline() { + [ -n "$COLUMNS" ] && MYCOLS="$COLUMNS" + [ -z "$MYCOLS" ] && MYCOLS="$(/usr/bin/tput cols 2>/dev/null)" + [ -z "$MYCOLS" ] && MYCOLS=16 + c=0 + printf '\033[1m' + while [ "$c" -lt "$MYCOLS" ]; do + printf '─' + c="$((c+1))" + done + printf '\033[0m\n' +} + +dline() { + [ -n "$COLUMNS" ] && MYCOLS="$COLUMNS" + [ -z "$MYCOLS" ] && MYCOLS="$(/usr/bin/tput cols 2>/dev/null)" + [ -z "$MYCOLS" ] && MYCOLS=16 + c=0 + while [ "$c" -lt "$MYCOLS" ]; do + printf '┄' + c="$((c+1))" + done + printf '\n' +} + +header() { + if [ -n "$1" ]; then + hline + printf ' \033[3m\033[1m%b\033[0m\n' "$1" + hline + fi +} + +footer() { + if [ -n "$1" ]; then + dline + printf '\033[3m\033[1m%b\033[0m\n' "$1" + fi +} + + +# 1. Find out about auxiliary helpers like rkhunter +declare NRSBIN RKHBIN +[ -z "$RKHUNTER" ] && RKHUNTER=2 +[ -z "$NEEDREST" ] && NEEDREST=2 +if [ "$NEEDREST" -gt 1 ] ; then + for bin in /usr/sbin/needrestart /usr/bin/needrestart; do + if [ -x "$bin" ]; then + NRSBIN="$bin" + NEEDREST=0 + break + fi + done +fi +if [ "$RKHUNTER" -gt 1 ] ; then + for bin in /usr/bin/rkhunter /usr/sbin/rkhunter; do + if [ -x "$bin" ]; then + RKHBIN="$bin" + RKHUNTER=0 + break + fi + done +fi + + +# 2. Patching. +case "$ID_LIKE" in + "debian") + APTBIN='/usr/bin/apt' + APTOPTS=( + '-o' 'Apt::Cmd::Disable-Script-Warning=true' + '-o' 'Dpkg::Progress-Fancy=False' + '-o' 'Apt::Color=False' + '-o' 'Dpkg::Use-Pty=False' + '-o' 'Quiet::NoUpdate=True' + '-o' 'APT::Get::AutomaticRemove=False' + '-o' 'APT::Get::AutomaticRemove::Kernels=False' + '-o' 'APT::Get::Assume-Yes=True' + ) + if [ "$RKHUNTER" -eq 0 ]; then + header 'Starting rkhunter check' + "$RKHBIN" -c --sk || exit 120 + fi + # 2.1. Package list refresh + header 'Starting package list update' + "$APTBIN" "${APTOPTS[@]}" update || exit 110 + ULIST="$("$APTBIN" "${APTOPTS[@]}" -q list --upgradable | grep -iP '^[0-9a-z_:\-+\.]+/.+' | sed 's/^\([^/]\+\).*/\1/')" + # Only one update will be one update with or without line-break, and NO update will be also with or without line-break. + # Solution: Always add a line-break, and grep away empty lines. + UPDATENUM="$(printf '%b\n' "$ULIST" | grep -vcP '^$')" + printf '\033[3m\033[1m%b update(s) found.\033[0m\n' "$UPDATENUM" + # 2.2. Package update. + # 2.2.1. No updates found? + if [ "$UPDATENUM" -lt 1 ]; then + printf '\033[3m\033[1m\033[2mSkipping updates.\033[0m\n' + else + # 2.2.2. Updates found? + header 'Starting package updates' + "$APTBIN" "${APTOPTS[@]}" full-upgrade || exit 112 + header 'Starting package auto-removal' + "$APTBIN" "${APTOPTS[@]}" --purge autoremove || exit 113 + # 2.2.3. Package file index update + if [ -x /usr/bin/apt-file ]; then + printf 'Starting apt-file update' + /usr/bin/apt-file "${APTOPTS[@]}" update || true + fi + if [ "$RKHUNTER" -eq 0 ]; then + header 'Starting rkhunter update' + "$RKHBIN" --propupd || exit 121 + fi + # 2.2.4. Requirement for reboot + if [ "$NEEDREST" -eq 0 ]; then + header 'Starting needrestart investigation' + "$NRSBIN" -b + # Outdated comment (kind of), see $NEEDREST at the top of the file -- + # If we don't have needrestart, this will fail - which is OK, without + # a means of controlling whether reboot is necessary we will reboot in any case. + if ! "$NRSBIN" -p; then + footer 'Outdated libraries or kernel found, rebooting' + /usr/bin/systemctl reboot || reboot + else + if [ "$UPDATENUM" -gt 0 ]; then + if [ -x "$OSPBIN" ]; then + header 'Starting os_patching_fact_generation.sh' + ospstart="$(/usr/bin/date '+%s')" + "$OSPBIN" + ospend="$(/usr/bin/date '+%s')" + footer "...done ($((ospend - ospstart)) seconds)." + fi + fi + fi + elif [ "$NEEDREST" -gt 1 ]; then + footer 'No needrestart found, rebooting' + /usr/bin/systemctl reboot || reboot + fi + fi + ;; + "suse"*) + # Caution: + # 1. Broken package dependenciers will not be solved + # 2. Orphaned packages will be kept in-place + + header 'Refreshing zypper "services"' + mystart="$(/usr/bin/date '+%s')" + /usr/bin/zypper -q --non-interactive refresh-services && printf 'OK.\n' || exit 110 + myend="$(/usr/bin/date '+%s')" + footer "...done ($((myend - mystart)) seconds)." + + header 'Refreshing repository cache' + mystart="$(/usr/bin/date '+%s')" + /usr/bin/zypper -q --non-interactive refresh && printf 'OK.\n' || exit 111 + myend="$(/usr/bin/date '+%s')" + footer "...done ($((myend - mystart)) seconds)." + + # TODO: no amount of "-q" keeps zypper from delivering the verbose list of updates before + # installing them. If only the zypper guys were modern in thinking script or automation approaches... + header 'Running update' + mystart="$(/usr/bin/date '+%s')" + /usr/bin/zypper -q --no-refresh --non-interactive-include-reboot-patches \ + up -y --auto-agree-with-licenses --solver-focus 'Update' && printf 'OK.\n' || exit 112 + myend="$(/usr/bin/date '+%s')" + footer "...done ($((myend - mystart)) seconds)." + + header 'Running dist-upgrade' + mystart="$(/usr/bin/date '+%s')" + /usr/bin/zypper -q --no-refresh --non-interactive-include-reboot-patches \ + dup -y --allow-name-change --allow-arch-change --allow-vendor-change --no-allow-downgrade \ + --auto-agree-with-licenses --solver-focus 'Update' && printf 'OK.\n' || exit 113 + myend="$(/usr/bin/date '+%s')" + footer "...done ($((myend - mystart)) seconds)." + + # zypper: why deliver exit codes WHEN WE CAN TOSS EFFIN STRINGS AT THE CONSOLE ONLY + # also... too many people rather tend to localise their systems....: + export LANG=C # use "C" as safe haven, we DO NOT want this to fail + # yes, in the very recent part they invented "needs-rebooting", but that only checks + # core services and libraries... :( so we do both here. We want to be rather aggressive + # on unattended updates in that we reboot if there are lingering "programs". Any of them. + header 'Checking reboot requirement... ' + if ! /usr/bin/zypper -q needs-rebooting; then + # TODO: zypper being locked by another "application" delivers RC7 - is this reserved + # exclusively for this case? + footer 'Rebooting (zypper needs-rebooting)' + /usr/bin/systemctl reboot + elif [ "$(/usr/bin/zypper ps -sss 2>&1 | wc -l)" -gt 0 ]; then + footer 'Rebooting (zypper ps)' + /usr/bin/systemctl reboot + else + printf 'no reboot required.\n' + if [ -x "$OSPBIN" ]; then + header 'Starting os_patching_fact_generation.sh' + ospstart="$(/usr/bin/date '+%s')" + "$OSPBIN" + ospend="$(/usr/bin/date '+%s')" + footer "...done ($((ospend - ospstart)) seconds)." + fi + fi + ;; + "rhel"*|"centos"*) + # we do not use --skip-broken here - we keep our systems tidy, so any pollution may and should + # cause an error :-) + + header 'Starting package list update' + mystart="$(/usr/bin/date '+%s')" + /usr/bin/dnf -d1 makecache && printf 'OK.\n' || exit 110 + myend="$(/usr/bin/date '+%s')" + footer "...done ($((myend - mystart)) seconds)." + + header 'Starting package upgrade' + mystart="$(/usr/bin/date '+%s')" + /usr/bin/dnf --comment='os_patching_adhoc' -d1 --obsoletes --best -y upgrade &&\ + printf 'OK.\n' || exit 111 + myend="$(/usr/bin/date '+%s')" + footer "...done ($((myend - mystart)) seconds)." + + header 'Checking reboot requirement' + if ! /usr/bin/dnf -d1 needs-restarting -r; then + footer 'Outdated libraries or kernel found, rebooting.' + /usr/bin/systemctl reboot + else + if [ -x "$OSPBIN" ]; then + header 'Starting os_patching_fact_generation.sh' + ospstart="$(/usr/bin/date '+%s')" + "$OSPBIN" + ospend="$(/usr/bin/date '+%s')" + footer "...done ($((ospend - ospstart)) seconds)." + fi + fi + ;; +esac |
