#!/usr/bin/env sh usage() { echo "Usage: $(basename "$0") [-K|-s|-k]" echo echo "-K: Output the current kernel flavor" echo "-k: Only check for updated kernel version (default: enabled)" echo "-s: Check whether services need to be restarted (default: enabled)" } _chroot() { if test -e /.dockerenv then sudo -E chroot /rootfs bash -c "$*" else eval "$@" fi } arch_current_version() { # Remove the kernel flavor at the end # 5.4.22-1-lts -> 5.4.22-1 _chroot uname -r | sed 's/-[^0-9]*$//' } archarm_current_version() { arch_current_version } openwrt_current_version() { uname -r } fedora_current_version() { # Remove the Fedora version and arch at the end # 5.5.5-200.fc31.x86_64 -> 5.5.5-200 uname -r | sed -r 's/.fc[0-9]+.*//' } ubuntu_current_version() { arch_current_version } raspbian_current_version() { # Remove the architecture at the end # 4.19.97-v7+ -> 4.19.97 uname -r | sed -r 's/-v.+$//' } arch_latest_installed() { local package case "$1" in LTS) package=linux-lts ;; VFIO) package=linux-vfio ;; *) package=linux ;; esac _chroot pacman -Qi "$package" | awk '/Version/ {print $3}' } archarm_latest_installed() { local package case "$1" in *) package=linux-raspberrypi ;; esac _chroot pacman -Qi "$package" | awk '/Version/ {print $3}' } openwrt_latest_installed() { _chroot sudo opkg list-installed | awk '/kernel - / {print $NF}' | cut -d - -f 1 } fedora_latest_installed() { _chroot dnf list installed kernel | \ awk '{ print $2 }' | sort -rn | head -1 | sed -r 's/.fc[0-9]+$//g' } raspbian_latest_installed() { local val local kernel_file case "$(uname -a)" in armv7l) kernel_file="/boot/kernel7.img" ;; aarch64) kernel_file="/boot/kernel8.img" ;; *) kernel_file="/boot/kernel7l.img" ;; esac if _chroot test -e /usr/lib/needrestart/vmlinuz-get-version then val="$(_chroot /usr/lib/needrestart/vmlinuz-get-version "$kernel_file")" # echo "Unable to determine current kernel version. Please install needrestart." >&2 else # Download latest vmlinuz-get-version _chroot curl -qqsL -o /tmp/vmlinuz-get-version \ https://github.com/liske/needrestart/raw/master/lib/vmlinuz-get-version val="$(_chroot bash /tmp/vmlinuz-get-version "$kernel_file")" _chroot rm /tmp/vmlinuz-get-version fi # Extract version # Linux version 4.19.97-v7+ (dom@buildbot) (gcc version[...] -> 4.19.97 # Linux version 4.19.97+ (dom@buildbot) (gcc version[...] -> 4.19.97 echo "$val" | sed -n -r 's/Linux version ([0-9.]+)[-+]v?.*/\1/p' } ubuntu_latest_installed() { _chroot dpkg --list | grep linux-image | \ grep -v 'linux-image-generic' | \ awk '{ print $2 }' | \ sort -nr -k 4 -t '-' | head -1 | \ sed -r 's/linux-image-(.+)-generic/\1/' } arch_kernel_flavour() { case "$(_chroot uname -a)" in *vfio*) echo VFIO ;; *lts*) echo LTS ;; *) echo latest ;; esac } kernel_flavour() { case "$ID" in arch|antergos) arch_kernel_flavour ;; archarm|turrisos|openwrt|lede|fedora|ubuntu|neon|raspbian|debian) echo latest ;; *) echo "Unsupported distribution" >&2 exit 3 ;; esac } check_kernel_update() { local current_version local flavor local latest_installed_version flavor="$(kernel_flavour)" case "$ID" in arch|antergos) current_version=$(arch_current_version) latest_installed_version=$(arch_latest_installed "$flavor") ;; archarm) current_version=$(archarm_current_version) latest_installed_version=$(archarm_latest_installed "$flavor") ;; openwrt|lede|turrisos) current_version=$(openwrt_current_version "$flavor") latest_installed_version=$(openwrt_latest_installed "$flavor") ;; fedora) current_version=$(fedora_current_version "$flavor") latest_installed_version=$(fedora_latest_installed "$flavor") ;; ubuntu|neon|debian) current_version=$(ubuntu_current_version "$flavor") latest_installed_version=$(ubuntu_latest_installed "$flavor") ;; raspbian) current_version=$(raspbian_current_version "$flavor") latest_installed_version=$(raspbian_latest_installed "$flavor") ;; *) echo "Unsupported distribution" >&2 exit 3 ;; esac if test "$current_version" != "$latest_installed_version" then echo "Kernel update: $current_version -> $latest_installed_version" return 1 fi return 0 } check_services() { local failed=0 local need_r if _chroot sudo needrestart --help >/dev/null 2>&1 then # shellcheck disable=2024 need_r="$(_chroot sudo needrestart -m a -b -n -r l -l -p 2>/dev/null)" else echo "ERROR: Please install needrestart" >&2 fi if echo "$need_r" | grep -q CRIT then echo "$need_r" failed=1 fi case "$ID" in ubuntu|neon|raspbian) if _chroot test -e /var/run/reboot-required then echo "/var/run/reboot-required is present on the system" failed=1 fi ;; fedora) needs_r=$(_chroot sudo needs-restarting -r) if test $? -eq 1 then echo "$needs_r" fi ;; esac return $failed } reboot_check() { local reboot_required=0 local message local KERNEL MISC local tmp if test "$#" -eq 0 then KERNEL=1 SERVICES=1 else case "$1" in -k|--kernel|kernel|k) KERNEL=1 ;; -s|--services|--svc|services|svc|s) SERVICES=1 ;; esac fi if test -n "$KERNEL" then tmp=$(check_kernel_update) if test $? -ne 0 then reboot_required=1 message="$tmp" fi fi if test -n "$SERVICES" then tmp=$(check_services) if test $? -ne 0 then reboot_required=1 if test -z "$message" then message="$tmp" else message="$message\n\n$tmp" fi fi fi if test "$reboot_required" = "0" then message="No reboot required ✔" fi # shellcheck disable=2039 if test "$(echo -e)" != "-e" then echo -e "$message" else # printf "%s\n" "$message" echo "$message" fi } determine_os() { local os_id os_id="$(_chroot cat /etc/os-release | sed -nr 's/^ID="?([^"]+)"?/\1/p')" if test -z "$os_id" then # Old (pre 19.07.1) OpenWRT version don't carry an /etc/os-release if _chroot test -r /etc/openwrt_version then os_id=openwrt fi echo "$os_id" fi echo "$os_id" } ID="$(determine_os)" case "$1" in help|h|--help|-h) usage ;; -K) kernel_flavour ;; *) # -k: kernel only # -m: Misc. services only # NONE: both if test "$#" -gt 1 then shift fi reboot_check "$@" ;; esac # vim set ft=sh et ts=2 sw=2 :