#!/bin/sh
#
#  Copyright (c) 2019 by Emmett1  (emmett1.2miligrams@gmail.com)
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
#
#  script to detect broken kernel modules after kernel update
#  need to use with 'scratchpkg'
#

export LANG=C

get_perlmodules() {
	command -v perl >/dev/null || return
	perlpath=$(dirname $(perl -V:sitearch | grep -o "'.*'" | sed "s/'//g"))
	for i in $(dirname $perlpath)/*; do
		[ "$perlpath" = "$i" ] && continue	
		brokenpkg="$brokenpkg $(scratch provide $i/$ | awk '{print $1}')"
	done
}

get_modules() {
	[ -f /lib/modules/KERNELVERSION ] || return
	KERVER=$(cat /lib/modules/KERNELVERSION)
	for i in /lib/modules/*; do
		case $i in
			/lib/modules/KERNELVERSION|/lib/modules/$KERVER) continue ;;
		esac
		brokenpkg="$brokenpkg $(scratch provide $i/$ | awk '{print $1}')"
	done
}

get_rubygem() {
	command -v gem >/dev/null || return
	gempath=$(gem env gemdir)
	for i in $(dirname $gempath)/*; do
		[ "$gempath" = "$i" ] && continue
		brokenpkg="$brokenpkg $(scratch provide $i/$ | awk '{print $1}')"
	done
}

sort_modules() {
	for all in $(scratch deplist $brokenpkg | cut -d ' ' -f2); do
		for r in $brokenpkg; do
			if [ $r = $all ]; then
				if [ -z "$order" ]; then
					order="$all"
				else
					order="$order $all"
				fi
				break
			fi
		done
	done
}

confirm() {
	printf "$1 (Y/n) "
	read -r response
	case "$response" in
		[Nn][Oo]|[Nn]) echo "$2"; return 2 ;;
		*) : ;;
	esac
	return 0
}

usage() {
	cat << EOF
Usage:
  $(basename $0) [options]
  
Options:
  -r     rebuild & reinstall broken package
  -y     dont ask user confirmation to rebuild package (use with -r)
  -h     print this help message

EOF
}

parse_opt() {
	while [ "$1" ]; do
		case $1 in
			-r) REBUILD=1 ;;
			-y) YES=1 ;;
			-h) usage; exit 0 ;;
			*)  echo "Invalid option ($1)"; exit 1 ;;
		esac
		shift
	done
}

parse_opt $@

if [ "$REBUILD" ] && [ "$(id -u)" != 0 ]; then
	echo "Rebuild broken packages required root!"
	exit 1
fi

get_modules
get_perlmodules
get_rubygem

if [ "$brokenpkg" ]; then
	sort_modules
else
	echo "No broken packages found."
	exit 0
fi

if [ "$REBUILD" = 1 ]; then
	[ "$YES" ] || {
		echo
		echo "Package will be rebuild & reinstall by this order:"
		echo " $order"
		echo
		confirm "Continue rebuild & reinstall broken packages?" "Operation cancelled."
	}
	for p in $order; do
		scratch build -f $p || exit 1
		scratch install -r $p || exit 1
	done
else
	echo "Broken packages:"
	for p in $order; do
		echo " $p"
	done
fi

exit 0
